From 7f4db7c80779ecbc57d1146654daf0acfe18de66 Mon Sep 17 00:00:00 2001 From: rus Date: Mon, 9 Nov 2009 20:58:24 +0000 Subject: merge from trunk git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/profile-stdlib@154052 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 3971 ++++- gcc/DATESTAMP | 2 +- gcc/Makefile.in | 135 +- gcc/ada/ChangeLog | 475 + gcc/ada/Makefile.rtl | 3 + gcc/ada/a-direct.adb | 7 + gcc/ada/a-ngelfu.adb | 19 +- gcc/ada/a-ngrear.adb | 6 +- gcc/ada/a-reatim.adb | 15 +- gcc/ada/a-rttiev.adb | 8 +- gcc/ada/a-ststio.adb | 6 +- gcc/ada/a-textio.adb | 156 +- gcc/ada/a-textio.ads | 50 +- gcc/ada/a-tideau.adb | 7 +- gcc/ada/a-tideio.adb | 1 - gcc/ada/a-tirsfi.adb | 39 + gcc/ada/a-tirsfi.ads | 40 + gcc/ada/a-wichun.adb | 0 gcc/ada/a-wichun.ads | 0 gcc/ada/a-widcha.ads | 0 gcc/ada/a-witeio.adb | 153 +- gcc/ada/a-witeio.ads | 53 +- gcc/ada/a-wrstfi.adb | 39 + gcc/ada/a-wrstfi.ads | 41 + gcc/ada/a-wtdeio.adb | 10 +- gcc/ada/a-wtedit.adb | 34 +- gcc/ada/a-zrstfi.adb | 39 + gcc/ada/a-zrstfi.ads | 41 + gcc/ada/a-ztdeau.adb | 7 +- gcc/ada/a-ztdeio.adb | 10 +- gcc/ada/a-ztedit.adb | 19 +- gcc/ada/a-ztexio.adb | 147 +- gcc/ada/a-ztexio.ads | 68 +- gcc/ada/adaint.c | 565 +- gcc/ada/adaint.h | 51 +- gcc/ada/ali.adb | 2 +- gcc/ada/bcheck.adb | 2 +- gcc/ada/checks.adb | 9 +- gcc/ada/env.c | 5 +- gcc/ada/exp_aggr.adb | 10 +- gcc/ada/exp_attr.adb | 22 +- gcc/ada/exp_ch3.adb | 134 +- gcc/ada/exp_ch4.adb | 142 +- gcc/ada/exp_ch4.ads | 9 +- gcc/ada/exp_ch9.adb | 35 +- gcc/ada/exp_ch9.ads | 4 +- gcc/ada/exp_dbug.ads | 8 +- gcc/ada/gcc-interface/Make-lang.in | 451 +- gcc/ada/gcc-interface/Makefile.in | 17 +- gcc/ada/gcc-interface/ada-tree.h | 18 +- gcc/ada/gcc-interface/decl.c | 272 +- gcc/ada/gcc-interface/gigi.h | 34 +- gcc/ada/gcc-interface/misc.c | 5 +- gcc/ada/gcc-interface/trans.c | 164 +- gcc/ada/gcc-interface/utils.c | 136 +- gcc/ada/gcc-interface/utils2.c | 50 +- gcc/ada/gnat_rm.texi | 42 + gcc/ada/gnat_ugn.texi | 40 +- gcc/ada/gnatbind.adb | 24 +- gcc/ada/gnatcmd.adb | 1 + gcc/ada/gnatlink.adb | 19 +- gcc/ada/gnatname.adb | 1 + gcc/ada/init.c | 16 +- gcc/ada/link.c | 15 + gcc/ada/make.adb | 1272 +- gcc/ada/makeutl.adb | 35 +- gcc/ada/opt.ads | 7 +- gcc/ada/osint.adb | 448 +- gcc/ada/osint.ads | 83 +- gcc/ada/par-ch4.adb | 84 +- gcc/ada/prj-err.adb | 13 +- gcc/ada/prj-ext.adb | 5 +- gcc/ada/prj-nmsc.adb | 318 +- gcc/ada/prj-part.adb | 34 +- gcc/ada/prj-tree.adb | 5 +- gcc/ada/raise-gcc.c | 34 +- gcc/ada/s-crtl.ads | 3 + gcc/ada/s-fileio.adb | 300 +- gcc/ada/s-fileio.ads | 74 +- gcc/ada/s-os_lib.adb | 68 +- gcc/ada/s-os_lib.ads | 23 +- gcc/ada/s-osinte-rtems.ads | 1 + gcc/ada/s-stchop-rtems.adb | 5 +- gcc/ada/sem_aggr.adb | 141 +- gcc/ada/sem_attr.adb | 11 +- gcc/ada/sem_case.adb | 151 +- gcc/ada/sem_ch12.adb | 38 +- gcc/ada/sem_ch3.adb | 12 +- gcc/ada/sem_eval.adb | 2 +- gcc/ada/sem_prag.adb | 9 + gcc/ada/sem_res.adb | 33 +- gcc/ada/sem_scil.adb | 9 +- gcc/ada/sem_type.adb | 53 +- gcc/ada/sem_util.adb | 175 + gcc/ada/sem_util.ads | 9 + gcc/ada/sem_warn.adb | 138 + gcc/ada/sem_warn.ads | 5 + gcc/ada/styleg.adb | 7 +- gcc/ada/switch-m.adb | 1 + gcc/ada/tbuild.adb | 53 +- gcc/ada/tbuild.ads | 7 + gcc/ada/types.ads | 2 +- gcc/ada/usage.adb | 2 + gcc/ada/xsnamest.adb | 10 +- gcc/alias.c | 70 +- gcc/alloc-pool.c | 4 +- gcc/auto-inc-dec.c | 34 +- gcc/bb-reorder.c | 6 - gcc/builtins.c | 110 +- gcc/c-common.c | 171 +- gcc/c-common.h | 32 +- gcc/c-decl.c | 135 +- gcc/c-lex.c | 18 +- gcc/c-parser.c | 44 + gcc/c-ppoutput.c | 65 +- gcc/c-pragma.c | 44 +- gcc/c-pragma.h | 10 +- gcc/c-pretty-print.c | 12 +- gcc/c-tree.h | 4 + gcc/c-typeck.c | 311 +- gcc/c.opt | 6 +- gcc/calls.c | 11 +- gcc/cfgcleanup.c | 26 +- gcc/cfgexpand.c | 176 +- gcc/cfgloop.h | 1 + gcc/cfgloopmanip.c | 3 +- gcc/cgraph.c | 37 +- gcc/cgraph.h | 58 +- gcc/cgraphbuild.c | 40 +- gcc/cgraphunit.c | 102 +- gcc/collect2.c | 409 +- gcc/collect2.h | 2 +- gcc/combine.c | 218 +- gcc/common.opt | 29 + gcc/config.gcc | 30 +- gcc/config.host | 2 +- gcc/config.in | 24 + gcc/config/alpha/osf.h | 4 - gcc/config/arm/arm.c | 427 +- gcc/config/arm/arm.h | 73 +- gcc/config/arm/arm.md | 120 +- gcc/config/arm/arm_neon.h | 100 +- gcc/config/arm/bpabi.h | 6 +- gcc/config/arm/cortex-a9.md | 186 +- gcc/config/arm/fpa.md | 4 +- gcc/config/arm/linux-eabi.h | 2 +- gcc/config/arm/linux-elf.h | 2 +- gcc/config/arm/neon-gen.ml | 3 +- gcc/config/arm/neon.md | 3 +- gcc/config/arm/neon.ml | 3 +- gcc/config/arm/netbsd-elf.h | 2 +- gcc/config/arm/thumb2.md | 10 +- gcc/config/arm/unwind-arm.c | 1 - gcc/config/arm/vxworks.h | 2 +- gcc/config/avr/avr.c | 27 +- gcc/config/avr/avr.h | 2 - gcc/config/avr/avr.md | 52 +- gcc/config/avr/avr.opt | 4 - gcc/config/bfin/bfin.h | 3 - gcc/config/cris/cris-protos.h | 2 + gcc/config/cris/cris.c | 41 +- gcc/config/cris/cris.h | 27 +- gcc/config/cris/cris.md | 6 +- gcc/config/darwin.c | 11 + gcc/config/darwin10.h | 5 + gcc/config/fr30/fr30.h | 10 - gcc/config/frv/frv-protos.h | 1 + gcc/config/frv/frv.c | 38 + gcc/config/frv/frv.h | 53 +- gcc/config/h8300/h8300.c | 60 +- gcc/config/h8300/h8300.h | 11 + gcc/config/i386/cpuid.h | 4 +- gcc/config/i386/cygming.h | 5 +- gcc/config/i386/fma4intrin.h | 9 - gcc/config/i386/i386-c.c | 4 + gcc/config/i386/i386.c | 1082 +- gcc/config/i386/i386.h | 11 +- gcc/config/i386/i386.md | 3758 ++--- gcc/config/i386/i386.opt | 8 + gcc/config/i386/ia32intrin.h | 2 + gcc/config/i386/linux.h | 5 +- gcc/config/i386/linux64.h | 3 + gcc/config/i386/lwpintrin.h | 109 + gcc/config/i386/mingw.opt | 4 + gcc/config/i386/mingw32.h | 2 + gcc/config/i386/predicates.md | 4 +- gcc/config/i386/sol2-unwind.h | 208 + gcc/config/i386/sol2.h | 2 + gcc/config/i386/sse.md | 1541 +- gcc/config/i386/winnt-cxx.c | 160 +- gcc/config/i386/winnt.c | 37 +- gcc/config/i386/x86intrin.h | 16 +- gcc/config/i386/xopintrin.h | 771 + gcc/config/ia64/ia64.c | 43 +- gcc/config/m32c/m32c-protos.h | 3 +- gcc/config/m32c/m32c.c | 35 +- gcc/config/m32c/m32c.h | 6 +- gcc/config/m68hc11/m68hc11.h | 3 - gcc/config/m68k/m68k.c | 47 + gcc/config/mep/mep.h | 2 - gcc/config/mips/iris.h | 3 - gcc/config/mips/mips-protos.h | 2 + gcc/config/mips/mips.c | 415 +- gcc/config/mips/mips.h | 54 +- gcc/config/mips/mips.md | 89 +- gcc/config/mips/mips.opt | 4 + gcc/config/mips/predicates.md | 4 + gcc/config/mips/sdemtk.h | 4 +- gcc/config/mn10300/mn10300-protos.h | 3 +- gcc/config/mn10300/mn10300.c | 30 +- gcc/config/mn10300/mn10300.h | 24 +- gcc/config/moxie/moxie.h | 4 - gcc/config/pa/pa.md | 25 +- gcc/config/pdp11/pdp11.h | 4 - gcc/config/picochip/picochip.h | 2 - gcc/config/rs6000/40x.md | 4 +- gcc/config/rs6000/440.md | 4 +- gcc/config/rs6000/476.md | 142 + gcc/config/rs6000/603.md | 4 +- gcc/config/rs6000/6xx.md | 4 +- gcc/config/rs6000/7450.md | 4 +- gcc/config/rs6000/7xx.md | 4 +- gcc/config/rs6000/8540.md | 4 +- gcc/config/rs6000/a2.md | 134 + gcc/config/rs6000/altivec.md | 2 +- gcc/config/rs6000/cell.md | 4 +- gcc/config/rs6000/e300c2c3.md | 4 +- gcc/config/rs6000/e500mc.md | 2 +- gcc/config/rs6000/mpc.md | 4 +- gcc/config/rs6000/option-defaults.h | 12 +- gcc/config/rs6000/power4.md | 4 +- gcc/config/rs6000/power5.md | 4 +- gcc/config/rs6000/power6.md | 7 +- gcc/config/rs6000/power7.md | 2 +- gcc/config/rs6000/predicates.md | 2 +- gcc/config/rs6000/rios1.md | 4 +- gcc/config/rs6000/rios2.md | 4 +- gcc/config/rs6000/rs6000-builtin.def | 990 ++ gcc/config/rs6000/rs6000.c | 253 +- gcc/config/rs6000/rs6000.h | 999 +- gcc/config/rs6000/rs6000.md | 16 +- gcc/config/rs6000/rs6000.opt | 6 +- gcc/config/rs6000/rs64.md | 4 +- gcc/config/rs6000/t-fprules | 1 + gcc/config/rs6000/t-rs6000 | 3 + gcc/config/rs6000/vxworks.h | 4 +- gcc/config/rx/constraints.md | 81 + gcc/config/rx/predicates.md | 288 + gcc/config/rx/rx-protos.h | 52 + gcc/config/rx/rx.c | 2517 +++ gcc/config/rx/rx.h | 659 + gcc/config/rx/rx.md | 1766 ++ gcc/config/rx/rx.opt | 98 + gcc/config/rx/t-rx | 32 + gcc/config/s390/2097.md | 34 +- gcc/config/s390/fixdfdi.h | 462 - gcc/config/s390/libgcc-glibc.ver | 116 - gcc/config/s390/s390.c | 8 +- gcc/config/s390/s390.h | 6 - gcc/config/s390/s390.md | 21 +- gcc/config/s390/t-crtstuff | 5 - gcc/config/s390/t-linux | 3 - gcc/config/s390/t-linux64 | 5 - gcc/config/s390/t-tpf | 9 - gcc/config/s390/tpf.h | 2 +- gcc/config/score/score.h | 3 - gcc/config/sh/sh.c | 207 +- gcc/config/sh/sh.md | 13 +- gcc/config/sparc/sol2-unwind.h | 458 + gcc/config/sparc/sol2.h | 2 + gcc/config/spu/cache.S | 43 + gcc/config/spu/cachemgr.c | 438 + gcc/config/spu/spu-c.c | 11 + gcc/config/spu/spu-elf.h | 10 +- gcc/config/spu/spu.c | 508 +- gcc/config/spu/spu.h | 20 +- gcc/config/spu/spu.opt | 21 + gcc/config/spu/spu_cache.h | 39 + gcc/config/spu/t-spu-elf | 33 +- gcc/config/stormy16/stormy16.h | 2 - gcc/config/vax/linux.h | 12 +- gcc/configure | 205 +- gcc/configure.ac | 47 +- gcc/convert.c | 12 +- gcc/coretypes.h | 7 + gcc/cp/ChangeLog | 393 + gcc/cp/call.c | 89 +- gcc/cp/class.c | 70 +- gcc/cp/cp-lang.c | 3 + gcc/cp/cp-tree.def | 2 +- gcc/cp/cp-tree.h | 51 +- gcc/cp/cvt.c | 1 + gcc/cp/cxx-pretty-print.c | 6 + gcc/cp/decl.c | 138 +- gcc/cp/decl2.c | 22 +- gcc/cp/error.c | 22 +- gcc/cp/mangle.c | 153 +- gcc/cp/method.c | 85 +- gcc/cp/name-lookup.c | 217 +- gcc/cp/optimize.c | 2 + gcc/cp/parser.c | 159 +- gcc/cp/pt.c | 406 +- gcc/cp/rtti.c | 34 +- gcc/cp/search.c | 7 +- gcc/cp/semantics.c | 167 +- gcc/cp/tree.c | 34 +- gcc/cp/typeck.c | 18 +- gcc/cse.c | 4 + gcc/cselib.c | 77 +- gcc/dbxout.c | 13 +- gcc/ddg.c | 4 +- gcc/debug.c | 16 + gcc/debug.h | 31 + gcc/defaults.h | 6 + gcc/df-problems.c | 23 +- gcc/df-scan.c | 21 +- gcc/doc/contrib.texi | 4 +- gcc/doc/cpp.texi | 2 - gcc/doc/extend.texi | 316 +- gcc/doc/install.texi | 52 +- gcc/doc/invoke.texi | 545 +- gcc/doc/md.texi | 78 +- gcc/doc/plugins.texi | 12 +- gcc/doc/rtl.texi | 10 + gcc/doc/sourcebuild.texi | 56 +- gcc/doc/tm.texi | 203 +- gcc/dse.c | 23 +- gcc/dwarf2out.c | 682 +- gcc/emit-rtl.c | 89 +- gcc/emit-rtl.h | 3 + gcc/except.c | 16 +- gcc/explow.c | 408 +- gcc/expmed.c | 31 +- gcc/expr.c | 218 +- gcc/expr.h | 32 +- gcc/final.c | 43 +- gcc/flags.h | 11 + gcc/fold-const.c | 31 +- gcc/fortran/ChangeLog | 347 +- gcc/fortran/arith.c | 5 +- gcc/fortran/check.c | 12 +- gcc/fortran/decl.c | 121 +- gcc/fortran/expr.c | 3 +- gcc/fortran/gfortran.h | 30 +- gcc/fortran/interface.c | 10 +- gcc/fortran/intrinsic.texi | 14 +- gcc/fortran/io.c | 6 +- gcc/fortran/match.c | 169 +- gcc/fortran/module.c | 115 +- gcc/fortran/options.c | 4 + gcc/fortran/parse.c | 59 +- gcc/fortran/parse.h | 1 + gcc/fortran/resolve.c | 632 +- gcc/fortran/symbol.c | 39 +- gcc/fortran/trans-array.c | 51 + gcc/fortran/trans-common.c | 5 +- gcc/fortran/trans-decl.c | 71 +- gcc/fortran/trans-expr.c | 312 +- gcc/fortran/trans-intrinsic.c | 2 + gcc/fortran/trans-openmp.c | 5 - gcc/fortran/trans-stmt.c | 157 +- gcc/fortran/trans-stmt.h | 1 + gcc/fortran/trans.c | 14 +- gcc/fwprop.c | 9 +- gcc/gcc-plugin.h | 1 + gcc/gcc.c | 144 +- gcc/gcse.c | 11 +- gcc/gengtype.c | 54 +- gcc/ggc-page.c | 60 +- gcc/gimple-iterator.c | 8 +- gcc/gimple-low.c | 75 +- gcc/gimple-pretty-print.c | 1 + gcc/gimple.c | 1238 +- gcc/gimple.h | 19 +- gcc/gimplify.c | 50 - gcc/graphite-sese-to-poly.c | 2 +- gcc/haifa-sched.c | 45 +- gcc/ifcvt.c | 22 +- gcc/input.h | 9 +- gcc/ipa-cp.c | 51 +- gcc/ipa-inline.c | 89 +- gcc/ipa-prop.c | 325 +- gcc/ipa-prop.h | 49 +- gcc/ipa-pure-const.c | 210 +- gcc/ipa-reference.c | 381 +- gcc/ipa-struct-reorg.c | 22 +- gcc/ipa.c | 126 +- gcc/ira-costs.c | 1 + gcc/ira-lives.c | 15 +- gcc/ira.c | 9 +- gcc/java/ChangeLog | 11 + gcc/java/config-lang.in | 2 +- gcc/java/mangle_name.c | 10 +- gcc/jump.c | 4 + gcc/langhooks-def.h | 18 +- gcc/langhooks.c | 52 + gcc/langhooks.h | 19 + gcc/loop-invariant.c | 621 +- gcc/lto-cgraph.c | 687 + gcc/lto-compress.c | 314 + gcc/lto-compress.h | 42 + gcc/lto-opts.c | 397 + gcc/lto-section-in.c | 489 + gcc/lto-section-out.c | 652 + gcc/lto-streamer-in.c | 2741 ++++ gcc/lto-streamer-out.c | 2551 +++ gcc/lto-streamer.c | 863 + gcc/lto-streamer.h | 1046 ++ gcc/lto-symtab.c | 676 + gcc/lto-wpa-fixup.c | 281 + gcc/lto-wrapper.c | 396 + gcc/lto/ChangeLog | 2628 +++ gcc/lto/Make-lang.in | 89 + gcc/lto/common.c | 46 + gcc/lto/common.h | 34 + gcc/lto/config-lang.in | 32 + gcc/lto/lang-specs.h | 24 + gcc/lto/lang.opt | 43 + gcc/lto/lto-elf.c | 729 + gcc/lto/lto-lang.c | 1188 ++ gcc/lto/lto-tree.h | 61 + gcc/lto/lto.c | 2021 +++ gcc/lto/lto.h | 60 + gcc/optabs.c | 6 +- gcc/optc-gen.awk | 1 + gcc/opts.c | 129 +- gcc/opts.h | 1 + gcc/output.h | 1 - gcc/params.def | 5 + gcc/params.h | 2 + gcc/passes.c | 324 +- gcc/plugin.c | 10 +- gcc/po/ChangeLog | 4 + gcc/po/gcc.pot | 15976 ++++++++++--------- gcc/print-rtl.c | 26 + gcc/print-tree.c | 7 +- gcc/real.c | 2 +- gcc/real.h | 3 + gcc/recog.c | 110 +- gcc/recog.h | 15 +- gcc/regcprop.c | 2 +- gcc/reginfo.c | 69 +- gcc/regmove.c | 33 +- gcc/reload.c | 108 +- gcc/reload.h | 2 +- gcc/reload1.c | 34 +- gcc/rtl.c | 26 + gcc/rtl.def | 4 + gcc/rtl.h | 25 +- gcc/rtlanal.c | 47 +- gcc/rtlhooks.c | 3 +- gcc/sched-deps.c | 143 +- gcc/sched-rgn.c | 6 +- gcc/sched-vis.c | 13 +- gcc/sdbout.c | 10 + gcc/sel-sched-dump.c | 6 +- gcc/sel-sched-ir.h | 3 + gcc/simplify-rtx.c | 127 +- gcc/stor-layout.c | 32 +- gcc/system.h | 2 +- gcc/target-def.h | 52 +- gcc/target.h | 52 +- gcc/targhooks.c | 120 +- gcc/targhooks.h | 14 +- gcc/testsuite/ChangeLog | 1793 ++- gcc/testsuite/ada/acats/norun.lst | 8 - gcc/testsuite/ada/acats/run_acats | 3 + gcc/testsuite/c-c++-common/builtin-offsetof.c | 29 + gcc/testsuite/c-c++-common/dfp/pr35620.c | 2 +- gcc/testsuite/c-c++-common/pr41935.c | 70 + gcc/testsuite/c-c++-common/restrict-1.c | 20 + gcc/testsuite/c-c++-common/restrict-2.c | 14 + gcc/testsuite/c-c++-common/restrict-4.c | 19 + gcc/testsuite/g++.dg/20090107-1.C | 12 + gcc/testsuite/g++.dg/20090121-1.C | 19 + gcc/testsuite/g++.dg/README | 1 + gcc/testsuite/g++.dg/abi/mangle32.C | 44 + gcc/testsuite/g++.dg/abi/mangle33.C | 19 + gcc/testsuite/g++.dg/abi/mangle34.C | 41 + gcc/testsuite/g++.dg/abi/pragma-pack1.C | 37 + gcc/testsuite/g++.dg/abi/regparm1.C | 40 + gcc/testsuite/g++.dg/abi/rtti3.C | 1 + gcc/testsuite/g++.dg/abi/thunk4.C | 1 + gcc/testsuite/g++.dg/abi/thunk5.C | 13 + gcc/testsuite/g++.dg/cpp/ucn-1.C | 13 + gcc/testsuite/g++.dg/cpp0x/auto12.C | 63 - gcc/testsuite/g++.dg/cpp0x/auto13.C | 11 - gcc/testsuite/g++.dg/cpp0x/auto3.C | 2 +- gcc/testsuite/g++.dg/cpp0x/auto6.C | 118 - gcc/testsuite/g++.dg/cpp0x/auto8.C | 16 - gcc/testsuite/g++.dg/cpp0x/decltype18.C | 5 + gcc/testsuite/g++.dg/cpp0x/deduce.C | 2 +- gcc/testsuite/g++.dg/cpp0x/defaulted14.C | 18 + gcc/testsuite/g++.dg/cpp0x/defaulted15.C | 43 + gcc/testsuite/g++.dg/cpp0x/defaulted16.C | 13 + gcc/testsuite/g++.dg/cpp0x/explicit4.C | 17 + gcc/testsuite/g++.dg/cpp0x/fntmpdefarg1.C | 7 + gcc/testsuite/g++.dg/cpp0x/initlist25.C | 17 + gcc/testsuite/g++.dg/cpp0x/inline-ns1.C | 12 + gcc/testsuite/g++.dg/cpp0x/inline-ns2.C | 25 + gcc/testsuite/g++.dg/cpp0x/inline-ns3.C | 24 + .../g++.dg/cpp0x/lambda/lambda-const-neg.C | 4 +- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv.C | 6 + .../g++.dg/cpp0x/lambda/lambda-direct-init.C | 14 + gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C | 8 + gcc/testsuite/g++.dg/cpp0x/lambda/lambda-mangle.C | 18 +- gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C | 31 + .../g++.dg/cpp0x/lambda/lambda-non-const.C | 1 - gcc/testsuite/g++.dg/cpp0x/linkage2.C | 33 + gcc/testsuite/g++.dg/cpp0x/nolinkage1.C | 1 + gcc/testsuite/g++.dg/cpp0x/rv-deduce.C | 8 + gcc/testsuite/g++.dg/cpp0x/rv-reinterpret.C | 11 + gcc/testsuite/g++.dg/cpp0x/rv-return.C | 18 + gcc/testsuite/g++.dg/cpp0x/trailing1.C | 118 + gcc/testsuite/g++.dg/cpp0x/trailing2.C | 16 + gcc/testsuite/g++.dg/cpp0x/trailing3.C | 63 + gcc/testsuite/g++.dg/cpp0x/trailing4.C | 11 + gcc/testsuite/g++.dg/cpp0x/trailing5.C | 10 + gcc/testsuite/g++.dg/cpp0x/variadic-throw.C | 4 +- gcc/testsuite/g++.dg/cpp0x/variadic95.C | 17 + gcc/testsuite/g++.dg/cpp0x/variadic96.C | 26 + gcc/testsuite/g++.dg/cpp0x/vt-40092.C | 21 + gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C | 18 + gcc/testsuite/g++.dg/debug/dwarf2/icf.C | 50 + .../g++.dg/debug/dwarf2/template-params-7.C | 21 + gcc/testsuite/g++.dg/dg.exp | 1 + gcc/testsuite/g++.dg/eh/pr41819.C | 21 + gcc/testsuite/g++.dg/ext/altivec-2.C | 4 +- gcc/testsuite/g++.dg/ext/always_inline-5.C | 28 + gcc/testsuite/g++.dg/ext/anon-struct4.C | 1 + gcc/testsuite/g++.dg/ext/raw-string-1.C | 96 + gcc/testsuite/g++.dg/ext/raw-string-2.C | 104 + gcc/testsuite/g++.dg/ext/raw-string-3.C | 58 + gcc/testsuite/g++.dg/ext/raw-string-4.C | 28 + gcc/testsuite/g++.dg/ext/raw-string-5.C | 23 + gcc/testsuite/g++.dg/ext/raw-string-6.C | 5 + gcc/testsuite/g++.dg/ext/raw-string-7.C | 23 + gcc/testsuite/g++.dg/ext/sync-3.C | 21 + gcc/testsuite/g++.dg/ext/utf-badconcat2.C | 15 + gcc/testsuite/g++.dg/ext/utf-dflt2.C | 12 + gcc/testsuite/g++.dg/ext/utf8-1.C | 45 + gcc/testsuite/g++.dg/ext/utf8-2.C | 21 + gcc/testsuite/g++.dg/ext/visibility/namespace3.C | 6 + gcc/testsuite/g++.dg/gomp/pr41967.C | 17 + gcc/testsuite/g++.dg/init/static-init2.C | 3 + gcc/testsuite/g++.dg/init/synth2.C | 17 + gcc/testsuite/g++.dg/ipa/20090113-1.C | 25 + gcc/testsuite/g++.dg/ipa/iinline-1.C | 2 +- gcc/testsuite/g++.dg/lookup/anon2.C | 6 +- gcc/testsuite/g++.dg/lookup/extern-c-redecl2.C | 21 + gcc/testsuite/g++.dg/lookup/extern-c-redecl3.C | 23 + gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C | 18 + gcc/testsuite/g++.dg/lookup/extern-c-redecl5.C | 18 + gcc/testsuite/g++.dg/lookup/koenig5.C | 32 +- gcc/testsuite/g++.dg/lookup/koenig6.C | 18 + gcc/testsuite/g++.dg/lookup/koenig7.C | 12 + gcc/testsuite/g++.dg/lookup/using16.C | 2 +- gcc/testsuite/g++.dg/lookup/using22.C | 17 + gcc/testsuite/g++.dg/lto/20080709_0.C | 11 + gcc/testsuite/g++.dg/lto/20080829_0.C | 9 + gcc/testsuite/g++.dg/lto/20080904_0.C | 37 + gcc/testsuite/g++.dg/lto/20080907_0.C | 3 + gcc/testsuite/g++.dg/lto/20080908-1_0.C | 36 + gcc/testsuite/g++.dg/lto/20080908-2_0.C | 3 + gcc/testsuite/g++.dg/lto/20080908-3_0.C | 14 + gcc/testsuite/g++.dg/lto/20080909-1_0.C | 3 + gcc/testsuite/g++.dg/lto/20080910-1_0.C | 2 + gcc/testsuite/g++.dg/lto/20080912-1_0.C | 3 + gcc/testsuite/g++.dg/lto/20080912_0.C | 4 + gcc/testsuite/g++.dg/lto/20080915_0.C | 29 + gcc/testsuite/g++.dg/lto/20080916_0.C | 12 + gcc/testsuite/g++.dg/lto/20080917_0.C | 29 + gcc/testsuite/g++.dg/lto/20080924_0.C | 16 + gcc/testsuite/g++.dg/lto/20080926_0.C | 4 + gcc/testsuite/g++.dg/lto/20081008_0.C | 36 + gcc/testsuite/g++.dg/lto/20081022.h | 8 + gcc/testsuite/g++.dg/lto/20081022_0.C | 11 + gcc/testsuite/g++.dg/lto/20081022_1.C | 7 + gcc/testsuite/g++.dg/lto/20081023_0.C | 14 + gcc/testsuite/g++.dg/lto/20081109-1_0.C | 5 + gcc/testsuite/g++.dg/lto/20081109-2_0.C | 15 + gcc/testsuite/g++.dg/lto/20081109_0.C | 28 + gcc/testsuite/g++.dg/lto/20081109_1.C | 4 + gcc/testsuite/g++.dg/lto/20081118-1_0.C | 27 + gcc/testsuite/g++.dg/lto/20081118-1_1.C | 12 + gcc/testsuite/g++.dg/lto/20081118_0.C | 20 + gcc/testsuite/g++.dg/lto/20081118_1.C | 20 + gcc/testsuite/g++.dg/lto/20081119-1.h | 8 + gcc/testsuite/g++.dg/lto/20081119-1_0.C | 12 + gcc/testsuite/g++.dg/lto/20081119-1_1.C | 9 + gcc/testsuite/g++.dg/lto/20081119_0.C | 24 + gcc/testsuite/g++.dg/lto/20081119_1.C | 18 + gcc/testsuite/g++.dg/lto/20081120-1_0.C | 10 + gcc/testsuite/g++.dg/lto/20081120-1_1.C | 8 + gcc/testsuite/g++.dg/lto/20081120-2_0.C | 13 + gcc/testsuite/g++.dg/lto/20081120-2_1.C | 11 + gcc/testsuite/g++.dg/lto/20081123_0.C | 8 + gcc/testsuite/g++.dg/lto/20081123_1.C | 16 + gcc/testsuite/g++.dg/lto/20081125.h | 15 + gcc/testsuite/g++.dg/lto/20081125_0.C | 18 + gcc/testsuite/g++.dg/lto/20081125_1.C | 7 + gcc/testsuite/g++.dg/lto/20081127_0.C | 2 + gcc/testsuite/g++.dg/lto/20081127_1.C | 3 + gcc/testsuite/g++.dg/lto/20081203_0.C | 5 + gcc/testsuite/g++.dg/lto/20081203_1.C | 4 + gcc/testsuite/g++.dg/lto/20081204-1_0.C | 14 + gcc/testsuite/g++.dg/lto/20081204-1_1.C | 3 + gcc/testsuite/g++.dg/lto/20081204-2_0.C | 10 + gcc/testsuite/g++.dg/lto/20081204-2_1.C | 14 + gcc/testsuite/g++.dg/lto/20081209_0.C | 18 + gcc/testsuite/g++.dg/lto/20081209_1.C | 9 + gcc/testsuite/g++.dg/lto/20081211-1.h | 6 + gcc/testsuite/g++.dg/lto/20081211-1_0.C | 19 + gcc/testsuite/g++.dg/lto/20081211-1_1.C | 6 + gcc/testsuite/g++.dg/lto/20081217-1_0.C | 28 + gcc/testsuite/g++.dg/lto/20081217-2_0.C | 20 + gcc/testsuite/g++.dg/lto/20081219_0.C | 72 + gcc/testsuite/g++.dg/lto/20081219_1.C | 42 + gcc/testsuite/g++.dg/lto/20090106_0.C | 203 + gcc/testsuite/g++.dg/lto/20090112_0.C | 11 + gcc/testsuite/g++.dg/lto/20090128_0.C | 88 + gcc/testsuite/g++.dg/lto/20090221_0.C | 53 + gcc/testsuite/g++.dg/lto/20090302_0.C | 9 + gcc/testsuite/g++.dg/lto/20090302_1.C | 7 + gcc/testsuite/g++.dg/lto/20090303_0.C | 22 + gcc/testsuite/g++.dg/lto/20090311-1.h | 22 + gcc/testsuite/g++.dg/lto/20090311-1_0.C | 34 + gcc/testsuite/g++.dg/lto/20090311-1_1.C | 28 + gcc/testsuite/g++.dg/lto/20090311_0.C | 13 + gcc/testsuite/g++.dg/lto/20090311_1.C | 13 + gcc/testsuite/g++.dg/lto/20090312.h | 2 + gcc/testsuite/g++.dg/lto/20090312_0.C | 14 + gcc/testsuite/g++.dg/lto/20090312_1.C | 21 + gcc/testsuite/g++.dg/lto/20090313_0.C | 5 + gcc/testsuite/g++.dg/lto/20090313_1.C | 12 + gcc/testsuite/g++.dg/lto/20090315_0.C | 9 + gcc/testsuite/g++.dg/lto/20090315_1.C | 7 + gcc/testsuite/g++.dg/lto/20091002-1_0.C | 58 + gcc/testsuite/g++.dg/lto/20091002-2_0.C | 20 + gcc/testsuite/g++.dg/lto/20091002-3_0.C | 15 + gcc/testsuite/g++.dg/lto/20091004-1_0.C | 35 + gcc/testsuite/g++.dg/lto/20091004-1_1.C | 26 + gcc/testsuite/g++.dg/lto/20091004-2_0.C | 29 + gcc/testsuite/g++.dg/lto/20091004-2_1.C | 32 + gcc/testsuite/g++.dg/lto/20091004-3_0.C | 18 + gcc/testsuite/g++.dg/lto/20091004-3_1.C | 16 + gcc/testsuite/g++.dg/lto/20091022-1_0.C | 13 + gcc/testsuite/g++.dg/lto/20091022-2_0.C | 12 + gcc/testsuite/g++.dg/lto/20091026-1_0.C | 11 + gcc/testsuite/g++.dg/lto/20091026-1_1.C | 14 + gcc/testsuite/g++.dg/lto/20091026-1_a.h | 9 + gcc/testsuite/g++.dg/lto/README | 35 + gcc/testsuite/g++.dg/lto/lto.exp | 58 + gcc/testsuite/g++.dg/lto/pr40818_0.C | 11 + gcc/testsuite/g++.dg/opt/eh5.C | 43 + gcc/testsuite/g++.dg/opt/inline16.C | 19 + gcc/testsuite/g++.dg/opt/thunk3-1.C | 6 + gcc/testsuite/g++.dg/opt/thunk4.C | 63 + gcc/testsuite/g++.dg/opt/vt1.C | 1 + gcc/testsuite/g++.dg/other/anon3.C | 2 +- gcc/testsuite/g++.dg/other/first-global.C | 2 +- gcc/testsuite/g++.dg/other/i386-2.C | 5 +- gcc/testsuite/g++.dg/other/i386-3.C | 4 +- gcc/testsuite/g++.dg/other/i386-5.C | 4 +- gcc/testsuite/g++.dg/other/i386-6.C | 4 +- gcc/testsuite/g++.dg/other/i386-7.C | 8 + gcc/testsuite/g++.dg/other/linkage2.C | 31 - gcc/testsuite/g++.dg/other/offsetof6.C | 26 + gcc/testsuite/g++.dg/other/ptrmem10.C | 29 + gcc/testsuite/g++.dg/other/ptrmem11.C | 21 + .../g++.dg/parse/attr-externally-visible-1.C | 2 +- gcc/testsuite/g++.dg/parse/eh-decl.C | 8 + gcc/testsuite/g++.dg/parse/error36.C | 17 + .../g++.dg/plugin/attribute_plugin-test-1.C | 2 +- gcc/testsuite/g++.dg/plugin/dumb_plugin.c | 2 +- gcc/testsuite/g++.dg/plugin/plugin.exp | 1 + gcc/testsuite/g++.dg/plugin/pragma_plugin-test-1.C | 18 + gcc/testsuite/g++.dg/plugin/pragma_plugin.c | 60 + gcc/testsuite/g++.dg/plugin/selfassign.c | 2 +- gcc/testsuite/g++.dg/rtti/typeid9.C | 21 + gcc/testsuite/g++.dg/template/arg2.C | 2 +- gcc/testsuite/g++.dg/template/crash56.C | 4 +- gcc/testsuite/g++.dg/template/error26.C | 2 +- gcc/testsuite/g++.dg/template/explicit-args2.C | 38 + gcc/testsuite/g++.dg/template/explicit-args3.C | 12 + gcc/testsuite/g++.dg/template/local4.C | 2 +- gcc/testsuite/g++.dg/template/nested3.C | 7 +- gcc/testsuite/g++.dg/template/overload11.C | 27 + gcc/testsuite/g++.dg/template/partial6.C | 31 + gcc/testsuite/g++.dg/template/scope3.C | 15 + gcc/testsuite/g++.dg/template/sfinae15.C | 23 + gcc/testsuite/g++.dg/template/sfinae16.C | 34 + gcc/testsuite/g++.dg/template/sizeof12.C | 19 + gcc/testsuite/g++.dg/template/spec35.C | 2 +- gcc/testsuite/g++.dg/torture/pr36191.C | 1 + gcc/testsuite/g++.dg/torture/pr40323.C | 2 +- gcc/testsuite/g++.dg/torture/pr41680.C | 23 + gcc/testsuite/g++.dg/torture/pr41775.C | 284 + gcc/testsuite/g++.dg/tree-ssa/copyprop.C | 2 +- gcc/testsuite/g++.dg/tree-ssa/nothrow-1.C | 3 +- gcc/testsuite/g++.dg/tree-ssa/restrict1.C | 20 + gcc/testsuite/g++.old-deja/g++.law/operators32.C | 4 +- gcc/testsuite/g++.old-deja/g++.ns/koenig5.C | 4 +- gcc/testsuite/g++.old-deja/g++.other/anon9.C | 5 - gcc/testsuite/g++.old-deja/g++.other/linkage1.C | 13 +- gcc/testsuite/g++.old-deja/g++.other/linkage2.C | 2 +- gcc/testsuite/g++.old-deja/g++.other/typename1.C | 4 +- gcc/testsuite/g++.old-deja/g++.pt/crash58.C | 12 +- gcc/testsuite/g++.old-deja/g++.pt/enum6.C | 2 +- gcc/testsuite/gcc.c-torture/compile/pr40556.c | 11 + gcc/testsuite/gcc.c-torture/compile/pr41182-1.c | 6 + gcc/testsuite/gcc.c-torture/compile/pr41634.c | 19 + gcc/testsuite/gcc.c-torture/compile/pr41646.c | 28 + gcc/testsuite/gcc.c-torture/compile/pr41661.c | 20 + gcc/testsuite/gcc.c-torture/compile/pr41728.c | 12 + .../gcc.c-torture/execute/builtins/builtins.exp | 2 +- .../gcc.c-torture/execute/builtins/lib/abs.c | 4 + .../gcc.c-torture/execute/builtins/lib/bfill.c | 1 + .../gcc.c-torture/execute/builtins/lib/bzero.c | 1 + .../gcc.c-torture/execute/builtins/lib/fprintf.c | 2 + .../gcc.c-torture/execute/builtins/lib/memchr.c | 1 + .../gcc.c-torture/execute/builtins/lib/memcmp.c | 1 + .../gcc.c-torture/execute/builtins/lib/memmove.c | 1 + .../gcc.c-torture/execute/builtins/lib/mempcpy.c | 1 + .../gcc.c-torture/execute/builtins/lib/memset.c | 1 + .../gcc.c-torture/execute/builtins/lib/printf.c | 2 + .../gcc.c-torture/execute/builtins/lib/sprintf.c | 1 + .../gcc.c-torture/execute/builtins/lib/stpcpy.c | 1 + .../gcc.c-torture/execute/builtins/lib/strcat.c | 1 + .../gcc.c-torture/execute/builtins/lib/strchr.c | 2 + .../gcc.c-torture/execute/builtins/lib/strcmp.c | 1 + .../gcc.c-torture/execute/builtins/lib/strcpy.c | 1 + .../gcc.c-torture/execute/builtins/lib/strcspn.c | 1 + .../gcc.c-torture/execute/builtins/lib/strlen.c | 1 + .../gcc.c-torture/execute/builtins/lib/strncat.c | 1 + .../gcc.c-torture/execute/builtins/lib/strncmp.c | 1 + .../gcc.c-torture/execute/builtins/lib/strncpy.c | 1 + .../gcc.c-torture/execute/builtins/lib/strpbrk.c | 1 + .../gcc.c-torture/execute/builtins/lib/strrchr.c | 2 + .../gcc.c-torture/execute/builtins/lib/strspn.c | 1 + .../gcc.c-torture/execute/builtins/lib/strstr.c | 1 + gcc/testsuite/gcc.c-torture/execute/execute.exp | 2 +- gcc/testsuite/gcc.c-torture/execute/ieee/ieee.exp | 2 +- gcc/testsuite/gcc.c-torture/execute/pr40668.c | 9 +- gcc/testsuite/gcc.c-torture/execute/pr41750.c | 68 + gcc/testsuite/gcc.c-torture/execute/pr41917.c | 21 + gcc/testsuite/gcc.c-torture/execute/pr41919.c | 39 + gcc/testsuite/gcc.c-torture/execute/pr41935.c | 25 + gcc/testsuite/gcc.c-torture/unsorted/unsorted.exp | 2 +- gcc/testsuite/gcc.dg/20081223-1.c | 5 + .../gcc.dg/Wstrict-aliasing-bogus-vla-1.c | 10 + gcc/testsuite/gcc.dg/autopar/outer-1.c | 33 + gcc/testsuite/gcc.dg/autopar/outer-2.c | 33 + gcc/testsuite/gcc.dg/autopar/outer-3.c | 33 + gcc/testsuite/gcc.dg/autopar/outer-4.c | 37 + gcc/testsuite/gcc.dg/autopar/outer-5.c | 50 + gcc/testsuite/gcc.dg/autopar/outer-6.c | 51 + gcc/testsuite/gcc.dg/cleanup-13.c | 319 + gcc/testsuite/gcc.dg/cpp/include6.c | 14 + gcc/testsuite/gcc.dg/cpp/separate-1.c | 4 +- gcc/testsuite/gcc.dg/cpp/spacing1.c | 1 + gcc/testsuite/gcc.dg/debug/dwarf2/inline3.c | 22 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-1.c | 18 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-2.c | 9 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-3.c | 18 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-4.c | 9 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c | 14 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-6.c | 8 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41543.c | 14 + gcc/testsuite/gcc.dg/debug/dwarf2/pr41695.c | 18 + gcc/testsuite/gcc.dg/debug/pr41264-1.c | 36 + gcc/testsuite/gcc.dg/debug/pr41343-1.c | 20 + gcc/testsuite/gcc.dg/debug/pr41717.c | 10 + gcc/testsuite/gcc.dg/debug/pr41893-1.c | 13 + gcc/testsuite/gcc.dg/debug/pr41893-2.c | 10 + gcc/testsuite/gcc.dg/debug/vta-1.c | 34 + gcc/testsuite/gcc.dg/debug/vta-2.c | 21 + gcc/testsuite/gcc.dg/debug/vta-3.c | 17 + gcc/testsuite/gcc.dg/guality/guality.exp | 77 +- gcc/testsuite/gcc.dg/guality/pr41447-1.c | 26 + gcc/testsuite/gcc.dg/guality/pr41616-1.c | 20 + gcc/testsuite/gcc.dg/inline-33.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipa-1.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipa-2.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipa-3.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipa-4.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipa-5.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipa-7.c | 2 +- gcc/testsuite/gcc.dg/ipa/ipacost-2.c | 2 +- gcc/testsuite/gcc.dg/lto/20080908_0.c | 16 + gcc/testsuite/gcc.dg/lto/20080917_0.c | 29 + gcc/testsuite/gcc.dg/lto/20080924_0.c | 9 + gcc/testsuite/gcc.dg/lto/20081024_0.c | 26 + gcc/testsuite/gcc.dg/lto/20081109_0.c | 3 + gcc/testsuite/gcc.dg/lto/20081111_0.c | 11 + gcc/testsuite/gcc.dg/lto/20081111_1.c | 7 + gcc/testsuite/gcc.dg/lto/20081112_0.c | 14 + gcc/testsuite/gcc.dg/lto/20081112_1.c | 13 + gcc/testsuite/gcc.dg/lto/20081115_0.c | 32 + gcc/testsuite/gcc.dg/lto/20081115_1.c | 11 + gcc/testsuite/gcc.dg/lto/20081115_2.c | 5 + gcc/testsuite/gcc.dg/lto/20081118_0.c | 28 + gcc/testsuite/gcc.dg/lto/20081118_1.c | 13 + gcc/testsuite/gcc.dg/lto/20081118_2.c | 11 + gcc/testsuite/gcc.dg/lto/20081120-1_0.c | 5 + gcc/testsuite/gcc.dg/lto/20081120-1_1.c | 3 + gcc/testsuite/gcc.dg/lto/20081120-2_0.c | 3 + gcc/testsuite/gcc.dg/lto/20081120-2_1.c | 2 + gcc/testsuite/gcc.dg/lto/20081125_0.c | 6 + gcc/testsuite/gcc.dg/lto/20081125_1.c | 4 + gcc/testsuite/gcc.dg/lto/20081126_0.c | 8 + gcc/testsuite/gcc.dg/lto/20081201-1_0.c | 33 + gcc/testsuite/gcc.dg/lto/20081201-1_1.c | 13 + gcc/testsuite/gcc.dg/lto/20081201-1_2.c | 7 + gcc/testsuite/gcc.dg/lto/20081201-2_0.c | 16 + gcc/testsuite/gcc.dg/lto/20081201-2_1.c | 5 + gcc/testsuite/gcc.dg/lto/20081202-1_0.c | 11 + gcc/testsuite/gcc.dg/lto/20081202-1_1.c | 10 + gcc/testsuite/gcc.dg/lto/20081202-2_0.c | 13 + gcc/testsuite/gcc.dg/lto/20081202-2_1.c | 16 + gcc/testsuite/gcc.dg/lto/20081204-1_0.c | 7 + gcc/testsuite/gcc.dg/lto/20081204-1_1.c | 5 + gcc/testsuite/gcc.dg/lto/20081204-2_0.c | 5 + gcc/testsuite/gcc.dg/lto/20081210-1_0.c | 21 + gcc/testsuite/gcc.dg/lto/20081212-1_0.c | 4 + gcc/testsuite/gcc.dg/lto/20081222_0.c | 11 + gcc/testsuite/gcc.dg/lto/20081222_0.h | 1 + gcc/testsuite/gcc.dg/lto/20081222_1.c | 16 + gcc/testsuite/gcc.dg/lto/20081224_0.c | 9 + gcc/testsuite/gcc.dg/lto/20081224_0.h | 3 + gcc/testsuite/gcc.dg/lto/20081224_1.c | 2 + gcc/testsuite/gcc.dg/lto/20090116_0.c | 12 + gcc/testsuite/gcc.dg/lto/20090120_0.c | 14 + gcc/testsuite/gcc.dg/lto/20090126-1_0.c | 7 + gcc/testsuite/gcc.dg/lto/20090126-2_0.c | 7 + gcc/testsuite/gcc.dg/lto/20090206-1_0.c | 10 + gcc/testsuite/gcc.dg/lto/20090206-2_0.c | 18 + gcc/testsuite/gcc.dg/lto/20090210_0.c | 6 + gcc/testsuite/gcc.dg/lto/20090210_1.c | 22 + gcc/testsuite/gcc.dg/lto/20090213_0.c | 11 + gcc/testsuite/gcc.dg/lto/20090213_1.c | 6 + gcc/testsuite/gcc.dg/lto/20090218-1_0.c | 4 + gcc/testsuite/gcc.dg/lto/20090218-1_1.c | 9 + gcc/testsuite/gcc.dg/lto/20090218-2_0.c | 3 + gcc/testsuite/gcc.dg/lto/20090218-2_1.c | 19 + gcc/testsuite/gcc.dg/lto/20090218_0.c | 7 + gcc/testsuite/gcc.dg/lto/20090218_1.c | 6 + gcc/testsuite/gcc.dg/lto/20090218_2.c | 6 + gcc/testsuite/gcc.dg/lto/20090218_3.c | 3 + gcc/testsuite/gcc.dg/lto/20090219_0.c | 28 + gcc/testsuite/gcc.dg/lto/20090312_0.c | 43 + gcc/testsuite/gcc.dg/lto/20090312_1.c | 9 + gcc/testsuite/gcc.dg/lto/20090313_0.c | 9 + gcc/testsuite/gcc.dg/lto/20090706-1_0.c | 42 + gcc/testsuite/gcc.dg/lto/20090706-2_0.c | 16 + gcc/testsuite/gcc.dg/lto/20090717_0.c | 4 + gcc/testsuite/gcc.dg/lto/20090717_1.c | 11 + gcc/testsuite/gcc.dg/lto/20090729_0.c | 4 + gcc/testsuite/gcc.dg/lto/20090729_1.c | 4 + gcc/testsuite/gcc.dg/lto/20090812_0.c | 11 + gcc/testsuite/gcc.dg/lto/20090812_1.c | 26 + gcc/testsuite/gcc.dg/lto/20090914-1_0.c | 13 + gcc/testsuite/gcc.dg/lto/20090914-2_0.c | 12 + gcc/testsuite/gcc.dg/lto/20091005-1_0.c | 3 + gcc/testsuite/gcc.dg/lto/20091005-1_1.c | 2 + gcc/testsuite/gcc.dg/lto/20091005-2_0.c | 11 + gcc/testsuite/gcc.dg/lto/20091006-1_0.c | 14 + gcc/testsuite/gcc.dg/lto/20091006-1_1.c | 2 + gcc/testsuite/gcc.dg/lto/20091006-2_0.c | 4 + gcc/testsuite/gcc.dg/lto/20091006-2_1.c | 1 + gcc/testsuite/gcc.dg/lto/20091006-2_2.c | 1 + gcc/testsuite/gcc.dg/lto/20091013-1_0.c | 21 + gcc/testsuite/gcc.dg/lto/20091013-1_1.c | 111 + gcc/testsuite/gcc.dg/lto/20091013-1_2.c | 220 + gcc/testsuite/gcc.dg/lto/20091014-1_0.c | 4 + gcc/testsuite/gcc.dg/lto/20091015-1_0.c | 5 + gcc/testsuite/gcc.dg/lto/20091015-1_1.c | 4 + gcc/testsuite/gcc.dg/lto/20091015-1_2.c | 5 + gcc/testsuite/gcc.dg/lto/20091015-1_a.h | 2 + gcc/testsuite/gcc.dg/lto/20091015-1_b.h | 2 + gcc/testsuite/gcc.dg/lto/20091016-1_0.c | 13 + gcc/testsuite/gcc.dg/lto/20091016-1_1.c | 18 + gcc/testsuite/gcc.dg/lto/20091016-1_a.h | 6 + gcc/testsuite/gcc.dg/lto/20091017-1_0.c | 15 + gcc/testsuite/gcc.dg/lto/20091017-1_1.c | 6 + gcc/testsuite/gcc.dg/lto/20091020-1_0.c | 8 + gcc/testsuite/gcc.dg/lto/20091020-1_1.c | 15 + gcc/testsuite/gcc.dg/lto/20091020-2_0.c | 18 + gcc/testsuite/gcc.dg/lto/20091020-2_1.c | 5 + gcc/testsuite/gcc.dg/lto/20091020-3_0.c | 20 + gcc/testsuite/gcc.dg/lto/20091027-1_0.c | 11 + gcc/testsuite/gcc.dg/lto/20091027-1_1.c | 9 + gcc/testsuite/gcc.dg/lto/README | 35 + gcc/testsuite/gcc.dg/lto/lto.exp | 57 + gcc/testsuite/gcc.dg/noncompile/pr40033-1.c | 7 + gcc/testsuite/gcc.dg/plugin/one_time_plugin.c | 6 +- gcc/testsuite/gcc.dg/plugin/selfassign.c | 2 +- gcc/testsuite/gcc.dg/pr41340.c | 68 + gcc/testsuite/gcc.dg/pr41345.c | 14 + gcc/testsuite/gcc.dg/pr41573.c | 15 + gcc/testsuite/gcc.dg/pr41574.c | 15 + gcc/testsuite/gcc.dg/pr41762.c | 31 + gcc/testsuite/gcc.dg/pr41783.c | 20 + gcc/testsuite/gcc.dg/pr41837.c | 38 + gcc/testsuite/gcc.dg/pr41841.c | 22 + gcc/testsuite/gcc.dg/pr41842.c | 8 + gcc/testsuite/gcc.dg/pr41935.c | 25 + gcc/testsuite/gcc.dg/pr41963.c | 36 + gcc/testsuite/gcc.dg/raw-string-1.c | 101 + gcc/testsuite/gcc.dg/raw-string-2.c | 109 + gcc/testsuite/gcc.dg/raw-string-3.c | 53 + gcc/testsuite/gcc.dg/raw-string-4.c | 28 + gcc/testsuite/gcc.dg/raw-string-5.c | 23 + gcc/testsuite/gcc.dg/raw-string-6.c | 5 + gcc/testsuite/gcc.dg/raw-string-7.c | 23 + gcc/testsuite/gcc.dg/tls/pie-1.c | 6 + gcc/testsuite/gcc.dg/torture/builtin-math-6.c | 49 +- gcc/testsuite/gcc.dg/torture/ipa-pta-1.c | 26 +- gcc/testsuite/gcc.dg/torture/pr23821.c | 29 + gcc/testsuite/gcc.dg/torture/pr26515.c | 27 + gcc/testsuite/gcc.dg/torture/pr38948.c | 101 + gcc/testsuite/gcc.dg/torture/pr41555.c | 119 + gcc/testsuite/gcc.dg/tree-ssa/foldstring-1.c | 6 +- gcc/testsuite/gcc.dg/tree-ssa/inline-3.c | 3 +- gcc/testsuite/gcc.dg/tree-ssa/ipa-cp-1.c | 30 +- gcc/testsuite/gcc.dg/tree-ssa/local-pure-const.c | 3 +- gcc/testsuite/gcc.dg/tree-ssa/pr41497.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/restrict-1.c | 20 - gcc/testsuite/gcc.dg/tree-ssa/restrict-2.c | 14 - gcc/testsuite/gcc.dg/tree-ssa/restrict-4.c | 19 - gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-23.c | 2 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-24.c | 9 +- gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-26.c | 27 + gcc/testsuite/gcc.dg/tree-ssa/useless-1.c | 6 +- gcc/testsuite/gcc.dg/utf-badconcat2.c | 15 + gcc/testsuite/gcc.dg/utf-dflt2.c | 12 + gcc/testsuite/gcc.dg/utf8-1.c | 45 + gcc/testsuite/gcc.dg/utf8-2.c | 26 + .../gcc.dg/vect/costmodel/i386/costmodel-vect-31.c | 6 +- .../gcc.dg/vect/costmodel/i386/costmodel-vect-33.c | 2 +- .../vect/costmodel/x86_64/costmodel-vect-31.c | 5 +- .../vect/costmodel/x86_64/costmodel-vect-33.c | 2 +- .../gcc.dg/vect/no-section-anchors-vect-31.c | 5 +- .../gcc.dg/vect/no-section-anchors-vect-64.c | 5 +- .../gcc.dg/vect/no-section-anchors-vect-66.c | 5 +- .../gcc.dg/vect/no-section-anchors-vect-68.c | 5 +- .../gcc.dg/vect/no-section-anchors-vect-69.c | 5 +- gcc/testsuite/gcc.dg/vect/slp-25.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-109.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-26.c | 6 +- gcc/testsuite/gcc.dg/vect/vect-28.c | 4 +- gcc/testsuite/gcc.dg/vect/vect-33.c | 4 +- gcc/testsuite/gcc.dg/vect/vect-42.c | 4 +- gcc/testsuite/gcc.dg/vect/vect-44.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-50.c | 6 +- gcc/testsuite/gcc.dg/vect/vect-54.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-56.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-58.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-60.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-70.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-87.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-88.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-89.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-91.c | 3 +- gcc/testsuite/gcc.dg/vect/vect-92.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-93.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-95.c | 5 +- gcc/testsuite/gcc.dg/vect/vect-96.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c | 8 +- gcc/testsuite/gcc.dg/vect/vect-multitypes-3.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-multitypes-4.c | 4 +- gcc/testsuite/gcc.dg/vect/vect-multitypes-6.c | 2 +- gcc/testsuite/gcc.target/arm/neon-thumb2-move.c | 98 + gcc/testsuite/gcc.target/arm/neon/vfp-shift-a2t2.c | 27 + gcc/testsuite/gcc.target/arm/pr40835.c | 55 + gcc/testsuite/gcc.target/arm/thumb-bitfld1.c | 19 + gcc/testsuite/gcc.target/arm/thumb-branch1.c | 11 + gcc/testsuite/gcc.target/arm/thumb-ltu.c | 12 + gcc/testsuite/gcc.target/avr/torture/pr41885.c | 123 + gcc/testsuite/gcc.target/i386/brokensqrt.c | 29 + gcc/testsuite/gcc.target/i386/cold-attribute-4.s | 41 - gcc/testsuite/gcc.target/i386/i386.exp | 26 + gcc/testsuite/gcc.target/i386/incoming-10.c | 19 + gcc/testsuite/gcc.target/i386/incoming-11.c | 18 + gcc/testsuite/gcc.target/i386/incoming-12.c | 20 + gcc/testsuite/gcc.target/i386/incoming-13.c | 15 + gcc/testsuite/gcc.target/i386/incoming-14.c | 15 + gcc/testsuite/gcc.target/i386/incoming-15.c | 15 + gcc/testsuite/gcc.target/i386/incoming-6.c | 17 + gcc/testsuite/gcc.target/i386/incoming-7.c | 16 + gcc/testsuite/gcc.target/i386/incoming-8.c | 18 + gcc/testsuite/gcc.target/i386/incoming-9.c | 18 + .../gcc.target/i386/math-torture/math-torture.exp | 2 +- gcc/testsuite/gcc.target/i386/ms_hook_prologue.c | 29 + gcc/testsuite/gcc.target/i386/pic-1.c | 1 + gcc/testsuite/gcc.target/i386/pr37843-4.c | 13 + gcc/testsuite/gcc.target/i386/pr41900.c | 13 + gcc/testsuite/gcc.target/i386/sse-12.c | 4 +- gcc/testsuite/gcc.target/i386/sse-13.c | 10 +- gcc/testsuite/gcc.target/i386/sse-14.c | 11 +- gcc/testsuite/gcc.target/i386/sse-22.c | 14 +- gcc/testsuite/gcc.target/i386/sse-23.c | 15 +- gcc/testsuite/gcc.target/i386/sse-recip-vec.c | 3 +- gcc/testsuite/gcc.target/i386/sse-recip.c | 3 +- gcc/testsuite/gcc.target/i386/xop-check.h | 20 + gcc/testsuite/gcc.target/i386/xop-haddX.c | 206 + gcc/testsuite/gcc.target/i386/xop-hadduX.c | 207 + gcc/testsuite/gcc.target/i386/xop-hsubX.c | 128 + .../gcc.target/i386/xop-imul32widen-vector.c | 36 + gcc/testsuite/gcc.target/i386/xop-imul64-vector.c | 36 + gcc/testsuite/gcc.target/i386/xop-pcmov.c | 23 + gcc/testsuite/gcc.target/i386/xop-pcmov2.c | 23 + gcc/testsuite/gcc.target/i386/xop-rotate1-vector.c | 35 + gcc/testsuite/gcc.target/i386/xop-rotate2-vector.c | 35 + gcc/testsuite/gcc.target/i386/xop-rotate3-vector.c | 34 + gcc/testsuite/gcc.target/i386/xop-shift1-vector.c | 35 + gcc/testsuite/gcc.target/i386/xop-shift2-vector.c | 35 + gcc/testsuite/gcc.target/i386/xop-shift3-vector.c | 35 + gcc/testsuite/gcc.target/m68k/pr41302.c | 14 + gcc/testsuite/gcc.target/mips/mips.exp | 1 + .../gcc.target/mips/mmcount-ra-address-1.c | 7 + .../gcc.target/mips/mmcount-ra-address-2.c | 8 + .../gcc.target/mips/mmcount-ra-address-3.c | 9 + gcc/testsuite/gcc.target/mips/mult-1.c | 14 + gcc/testsuite/gcc.target/mips/truncate-6.c | 12 + gcc/testsuite/gcc.target/powerpc/altivec-33.c | 16 + gcc/testsuite/gcc.target/powerpc/altivec-4.c | 4 +- gcc/testsuite/gcc.target/powerpc/vsx-vectorize-1.c | 54 + gcc/testsuite/gcc.target/powerpc/vsx-vectorize-2.c | 64 + gcc/testsuite/gcc.target/powerpc/vsx-vectorize-3.c | 60 + gcc/testsuite/gcc.target/powerpc/vsx-vectorize-4.c | 60 + gcc/testsuite/gcc.target/powerpc/vsx-vectorize-5.c | 60 + gcc/testsuite/gcc.target/powerpc/vsx-vectorize-6.c | 64 + gcc/testsuite/gcc.target/powerpc/vsx-vectorize-7.c | 64 + gcc/testsuite/gcc.target/powerpc/vsx-vectorize-8.c | 64 + gcc/testsuite/gcc.target/powerpc/vsx-vrsave.c | 20 + gcc/testsuite/gcc.target/rx/builtins.c | 171 + gcc/testsuite/gcc.target/rx/i272091.c | 27 + gcc/testsuite/gcc.target/rx/interrupts.c | 58 + gcc/testsuite/gcc.target/rx/packed-struct.c | 55 + .../gcc.target/rx/rx-abi-function-tests.c | 159 + gcc/testsuite/gcc.target/rx/rx.exp | 43 + gcc/testsuite/gcc.target/rx/zero-width-bitfield.c | 32 + gcc/testsuite/gcc.target/spu/ea/cache1.c | 195 + gcc/testsuite/gcc.target/spu/ea/cast1.c | 43 + gcc/testsuite/gcc.target/spu/ea/cast2.c | 74 + gcc/testsuite/gcc.target/spu/ea/compile1.c | 109 + gcc/testsuite/gcc.target/spu/ea/compile2.c | 43 + gcc/testsuite/gcc.target/spu/ea/cppdefine.c | 36 + gcc/testsuite/gcc.target/spu/ea/ea.exp | 54 + gcc/testsuite/gcc.target/spu/ea/errors1.c | 67 + gcc/testsuite/gcc.target/spu/ea/errors2.c | 107 + gcc/testsuite/gcc.target/spu/ea/execute1.c | 41 + gcc/testsuite/gcc.target/spu/ea/execute2.c | 41 + gcc/testsuite/gcc.target/spu/ea/execute3.c | 39 + gcc/testsuite/gcc.target/spu/ea/ops1.c | 94 + gcc/testsuite/gcc.target/spu/ea/ops2.c | 94 + gcc/testsuite/gcc.target/spu/ea/options1.c | 22 + gcc/testsuite/gcc.target/spu/ea/pr41857.c | 29 + gcc/testsuite/gcc.target/spu/ea/test-sizes.c | 608 + gcc/testsuite/gcc.target/vsx-vectorize-1.c | 54 - gcc/testsuite/gcc.target/vsx-vectorize-2.c | 64 - gcc/testsuite/gcc.target/vsx-vectorize-3.c | 60 - gcc/testsuite/gcc.target/vsx-vectorize-4.c | 60 - gcc/testsuite/gcc.target/vsx-vectorize-5.c | 60 - gcc/testsuite/gcc.target/vsx-vectorize-6.c | 64 - gcc/testsuite/gcc.target/vsx-vectorize-7.c | 64 - gcc/testsuite/gcc.target/vsx-vectorize-8.c | 64 - gcc/testsuite/gfortran.dg/allocatable_scalar_4.f90 | 95 + gcc/testsuite/gfortran.dg/associated_target_3.f90 | 35 + .../gfortran.dg/assumed_charlen_function_6.f90 | 37 + gcc/testsuite/gfortran.dg/auto_dealloc_1.f90 | 59 + gcc/testsuite/gfortran.dg/block_2.f08 | 1 + gcc/testsuite/gfortran.dg/class_10.f03 | 32 + gcc/testsuite/gfortran.dg/class_11.f03 | 37 + gcc/testsuite/gfortran.dg/class_12.f03 | 45 + gcc/testsuite/gfortran.dg/class_2.f03 | 5 + gcc/testsuite/gfortran.dg/class_4a.f03 | 14 + gcc/testsuite/gfortran.dg/class_4b.f03 | 15 + gcc/testsuite/gfortran.dg/class_4c.f03 | 28 + gcc/testsuite/gfortran.dg/class_4d.f03 | 15 + gcc/testsuite/gfortran.dg/class_5.f03 | 31 + gcc/testsuite/gfortran.dg/class_6.f03 | 21 + gcc/testsuite/gfortran.dg/class_7.f03 | 21 + gcc/testsuite/gfortran.dg/class_8.f03 | 16 + gcc/testsuite/gfortran.dg/class_9.f03 | 68 + gcc/testsuite/gfortran.dg/class_allocate_1.f03 | 5 +- gcc/testsuite/gfortran.dg/class_allocate_2.f03 | 23 + gcc/testsuite/gfortran.dg/class_allocate_3.f03 | 39 + gcc/testsuite/gfortran.dg/class_allocate_4.f03 | 23 + gcc/testsuite/gfortran.dg/complex_intrinsic_8.f90 | 50 + gcc/testsuite/gfortran.dg/dynamic_dispatch_1.f03 | 84 + gcc/testsuite/gfortran.dg/dynamic_dispatch_2.f03 | 105 + gcc/testsuite/gfortran.dg/dynamic_dispatch_3.f03 | 91 + gcc/testsuite/gfortran.dg/dynamic_dispatch_4.f03 | 96 + gcc/testsuite/gfortran.dg/dynamic_dispatch_5.f03 | 185 + gcc/testsuite/gfortran.dg/equiv_8.f90 | 7 + gcc/testsuite/gfortran.dg/extends_8.f03 | 17 + gcc/testsuite/gfortran.dg/fmt_error_10.f | 29 + gcc/testsuite/gfortran.dg/fmt_error_9.f | 29 + gcc/testsuite/gfortran.dg/goto_6.f | 24 + gcc/testsuite/gfortran.dg/goto_7.f | 14 + gcc/testsuite/gfortran.dg/goto_8.f90 | 31 + gcc/testsuite/gfortran.dg/guality/arg1.f90 | 15 + gcc/testsuite/gfortran.dg/guality/guality.exp | 29 + gcc/testsuite/gfortran.dg/guality/pr41558.f90 | 10 + gcc/testsuite/gfortran.dg/intent_out_6.f90 | 39 + gcc/testsuite/gfortran.dg/interface_abstract_4.f90 | 35 + gcc/testsuite/gfortran.dg/lto/20091015-1_0.f | 8 + gcc/testsuite/gfortran.dg/lto/20091015-1_1.f | 4 + gcc/testsuite/gfortran.dg/lto/20091015-1_2.f | 5 + gcc/testsuite/gfortran.dg/lto/20091016-1_0.f90 | 12 + gcc/testsuite/gfortran.dg/lto/20091028-1_0.f90 | 9 + gcc/testsuite/gfortran.dg/lto/20091028-1_1.c | 11 + gcc/testsuite/gfortran.dg/lto/20091028-2_0.f90 | 9 + gcc/testsuite/gfortran.dg/lto/20091028-2_1.c | 11 + gcc/testsuite/gfortran.dg/lto/lto.exp | 57 + gcc/testsuite/gfortran.dg/lto/pr40724_0.f | 3 + gcc/testsuite/gfortran.dg/lto/pr40724_1.f | 3 + gcc/testsuite/gfortran.dg/lto/pr40725_0.f03 | 16 + gcc/testsuite/gfortran.dg/lto/pr40725_1.c | 12 + gcc/testsuite/gfortran.dg/lto/pr41069_0.f90 | 7 + gcc/testsuite/gfortran.dg/lto/pr41069_1.f90 | 10 + gcc/testsuite/gfortran.dg/lto/pr41069_2.f90 | 9 + gcc/testsuite/gfortran.dg/lto/pr41521_0.f90 | 9 + gcc/testsuite/gfortran.dg/lto/pr41521_1.f90 | 9 + gcc/testsuite/gfortran.dg/lto/pr41764_0.f | 13 + .../gfortran.dg/missing_optional_dummy_6.f90 | 60 + gcc/testsuite/gfortran.dg/module_md5_1.f90 | 2 +- gcc/testsuite/gfortran.dg/round_2.f03 | 24 + gcc/testsuite/gfortran.dg/same_type_as_2.f03 | 5 +- gcc/testsuite/gfortran.dg/select_type_1.f03 | 4 +- gcc/testsuite/gfortran.dg/select_type_5.f03 | 47 + gcc/testsuite/gfortran.dg/select_type_6.f03 | 38 + gcc/testsuite/gfortran.dg/select_type_7.f03 | 40 + gcc/testsuite/gfortran.dg/transfer_intrinsic_3.f90 | 38 + gcc/testsuite/gfortran.dg/typebound_operator_2.f03 | 1 - gcc/testsuite/gfortran.dg/typebound_operator_4.f03 | 4 +- .../gfortran.dg/vect/fast-math-pr38968.f90 | 1 + gcc/testsuite/gfortran.dg/vect/vect-2.f90 | 9 +- gcc/testsuite/gfortran.dg/vect/vect-3.f90 | 6 +- gcc/testsuite/gfortran.dg/vect/vect-4.f90 | 5 +- gcc/testsuite/gfortran.dg/vect/vect-5.f90 | 5 +- gcc/testsuite/gfortran.dg/whole_file_5.f90 | 2 +- gcc/testsuite/gfortran.dg/whole_file_6.f90 | 2 +- .../gfortran.fortran-torture/compile/pr41654.f90 | 15 + gcc/testsuite/gnat.dg/aggr11.adb | 17 + gcc/testsuite/gnat.dg/aggr11_pkg.ads | 14 + gcc/testsuite/gnat.dg/discr21.adb | 34 + gcc/testsuite/gnat.dg/discr21.ads | 5 + gcc/testsuite/gnat.dg/discr21_pkg.ads | 19 + gcc/testsuite/gnat.dg/discr22.adb | 23 + gcc/testsuite/gnat.dg/loop_optimization7.adb | 16 + gcc/testsuite/gnat.dg/loop_optimization7.ads | 9 + gcc/testsuite/gnat.dg/loop_optimization7_pkg.ads | 10 + gcc/testsuite/gnat.dg/nested_proc.adb | 33 - gcc/testsuite/gnat.dg/nested_proc1.adb | 33 + gcc/testsuite/gnat.dg/nested_proc2.adb | 30 + gcc/testsuite/gnat.dg/noreturn1.adb | 15 + gcc/testsuite/gnat.dg/noreturn1.ads | 8 + gcc/testsuite/gnat.dg/noreturn2.adb | 23 + gcc/testsuite/gnat.dg/noreturn2.ads | 8 + gcc/testsuite/gnat.dg/null_pointer_deref1.adb | 21 + gcc/testsuite/gnat.dg/null_pointer_deref2.adb | 28 + gcc/testsuite/gnat.dg/opt3.adb | 11 + gcc/testsuite/gnat.dg/opt3_pkg.ads | 5 + gcc/testsuite/gnat.dg/opt4.adb | 22 + gcc/testsuite/gnat.dg/opt5.adb | 21 + gcc/testsuite/gnat.dg/pack14.adb | 16 + gcc/testsuite/gnat.dg/slice8.adb | 13 + gcc/testsuite/gnat.dg/slice8_pkg1.ads | 3 + gcc/testsuite/gnat.dg/slice8_pkg2.ads | 23 + gcc/testsuite/gnat.dg/slice8_pkg3.adb | 17 + gcc/testsuite/gnat.dg/slice8_pkg3.ads | 11 + gcc/testsuite/gnat.dg/specs/import_abstract.ads | 6 + gcc/testsuite/gnat.dg/specs/pack4.ads | 12 + gcc/testsuite/gnat.dg/specs/pack5.ads | 13 + gcc/testsuite/gnat.dg/specs/rep_clause4.ads | 42 + gcc/testsuite/gnat.dg/stack_check1.adb | 38 + gcc/testsuite/gnat.dg/stack_check2.adb | 43 + gcc/testsuite/gnat.dg/timer_cancel.adb | 38 + gcc/testsuite/gnat.dg/unchecked_convert4.adb | 24 + gcc/testsuite/lib/c-torture.exp | 9 + gcc/testsuite/lib/gcc-dg.exp | 13 +- gcc/testsuite/lib/gcc-gdb-test.exp | 91 + gcc/testsuite/lib/lto.exp | 511 + gcc/testsuite/lib/target-supports.exp | 73 +- gcc/testsuite/lib/torture-options.exp | 10 +- gcc/testsuite/obj-c++.dg/bitfield-1.mm | 2 +- gcc/testsuite/obj-c++.dg/bitfield-4.mm | 2 +- gcc/testsuite/obj-c++.dg/layout-1.mm | 2 +- gcc/timevar.def | 9 + gcc/tlink.c | 2 +- gcc/toplev.c | 21 + gcc/toplev.h | 1 + gcc/tree-cfg.c | 753 +- gcc/tree-chrec.h | 1 + gcc/tree-complex.c | 4 +- gcc/tree-dump.c | 4 + gcc/tree-eh.c | 204 +- gcc/tree-flow.h | 14 +- gcc/tree-inline.c | 9 +- gcc/tree-into-ssa.c | 29 +- gcc/tree-nested.c | 12 + gcc/tree-optimize.c | 5 +- gcc/tree-parloops.c | 68 +- gcc/tree-pass.h | 31 +- gcc/tree-pretty-print.c | 18 + gcc/tree-scalar-evolution.c | 15 +- gcc/tree-sra.c | 102 +- gcc/tree-ssa-address.c | 171 +- gcc/tree-ssa-alias.c | 93 +- gcc/tree-ssa-alias.h | 1 + gcc/tree-ssa-dce.c | 29 +- gcc/tree-ssa-dom.c | 26 +- gcc/tree-ssa-forwprop.c | 8 +- gcc/tree-ssa-ifcombine.c | 6 + gcc/tree-ssa-loop-im.c | 20 +- gcc/tree-ssa-loop-ivopts.c | 215 +- gcc/tree-ssa-math-opts.c | 126 +- gcc/tree-ssa-operands.c | 4 + gcc/tree-ssa-pre.c | 104 +- gcc/tree-ssa-reassoc.c | 2 - gcc/tree-ssa-sccvn.c | 4 +- gcc/tree-ssa-sink.c | 7 - gcc/tree-ssa-structalias.c | 251 +- gcc/tree-ssa.c | 250 +- gcc/tree-ssanames.c | 2 +- gcc/tree-vect-data-refs.c | 36 +- gcc/tree-vect-stmts.c | 10 +- gcc/tree-vrp.c | 13 +- gcc/tree.c | 363 +- gcc/tree.def | 12 +- gcc/tree.h | 45 +- gcc/unwind-dw2.c | 20 +- gcc/var-tracking.c | 102 +- gcc/varasm.c | 59 +- gcc/varpool.c | 35 +- gcc/vmsdbgout.c | 15 + 1239 files changed, 83503 insertions(+), 20544 deletions(-) create mode 100755 gcc/ada/a-tirsfi.adb create mode 100755 gcc/ada/a-tirsfi.ads mode change 100755 => 100644 gcc/ada/a-wichun.adb mode change 100755 => 100644 gcc/ada/a-wichun.ads mode change 100755 => 100644 gcc/ada/a-widcha.ads create mode 100644 gcc/ada/a-wrstfi.adb create mode 100644 gcc/ada/a-wrstfi.ads create mode 100755 gcc/ada/a-zrstfi.adb create mode 100755 gcc/ada/a-zrstfi.ads create mode 100644 gcc/config/i386/lwpintrin.h create mode 100644 gcc/config/i386/sol2-unwind.h create mode 100644 gcc/config/i386/xopintrin.h create mode 100644 gcc/config/rs6000/476.md create mode 100644 gcc/config/rs6000/a2.md create mode 100644 gcc/config/rs6000/rs6000-builtin.def create mode 100644 gcc/config/rx/constraints.md create mode 100644 gcc/config/rx/predicates.md create mode 100644 gcc/config/rx/rx-protos.h create mode 100644 gcc/config/rx/rx.c create mode 100644 gcc/config/rx/rx.h create mode 100644 gcc/config/rx/rx.md create mode 100644 gcc/config/rx/rx.opt create mode 100644 gcc/config/rx/t-rx delete mode 100644 gcc/config/s390/fixdfdi.h delete mode 100644 gcc/config/s390/libgcc-glibc.ver delete mode 100644 gcc/config/s390/t-crtstuff delete mode 100644 gcc/config/s390/t-linux delete mode 100644 gcc/config/s390/t-tpf create mode 100644 gcc/config/sparc/sol2-unwind.h create mode 100644 gcc/config/spu/cache.S create mode 100644 gcc/config/spu/cachemgr.c create mode 100644 gcc/config/spu/spu_cache.h create mode 100644 gcc/lto-cgraph.c create mode 100644 gcc/lto-compress.c create mode 100644 gcc/lto-compress.h create mode 100644 gcc/lto-opts.c create mode 100644 gcc/lto-section-in.c create mode 100644 gcc/lto-section-out.c create mode 100644 gcc/lto-streamer-in.c create mode 100644 gcc/lto-streamer-out.c create mode 100644 gcc/lto-streamer.c create mode 100644 gcc/lto-streamer.h create mode 100644 gcc/lto-symtab.c create mode 100644 gcc/lto-wpa-fixup.c create mode 100644 gcc/lto-wrapper.c create mode 100644 gcc/lto/ChangeLog create mode 100644 gcc/lto/Make-lang.in create mode 100644 gcc/lto/common.c create mode 100644 gcc/lto/common.h create mode 100644 gcc/lto/config-lang.in create mode 100644 gcc/lto/lang-specs.h create mode 100644 gcc/lto/lang.opt create mode 100644 gcc/lto/lto-elf.c create mode 100644 gcc/lto/lto-lang.c create mode 100644 gcc/lto/lto-tree.h create mode 100644 gcc/lto/lto.c create mode 100644 gcc/lto/lto.h create mode 100644 gcc/testsuite/c-c++-common/builtin-offsetof.c create mode 100644 gcc/testsuite/c-c++-common/pr41935.c create mode 100644 gcc/testsuite/c-c++-common/restrict-1.c create mode 100644 gcc/testsuite/c-c++-common/restrict-2.c create mode 100644 gcc/testsuite/c-c++-common/restrict-4.c create mode 100644 gcc/testsuite/g++.dg/20090107-1.C create mode 100644 gcc/testsuite/g++.dg/20090121-1.C create mode 100644 gcc/testsuite/g++.dg/abi/mangle32.C create mode 100644 gcc/testsuite/g++.dg/abi/mangle33.C create mode 100644 gcc/testsuite/g++.dg/abi/mangle34.C create mode 100644 gcc/testsuite/g++.dg/abi/pragma-pack1.C create mode 100644 gcc/testsuite/g++.dg/abi/regparm1.C create mode 100644 gcc/testsuite/g++.dg/abi/thunk5.C create mode 100644 gcc/testsuite/g++.dg/cpp/ucn-1.C delete mode 100644 gcc/testsuite/g++.dg/cpp0x/auto12.C delete mode 100644 gcc/testsuite/g++.dg/cpp0x/auto13.C delete mode 100644 gcc/testsuite/g++.dg/cpp0x/auto6.C delete mode 100644 gcc/testsuite/g++.dg/cpp0x/auto8.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/decltype18.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted14.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted15.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/defaulted16.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/explicit4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/fntmpdefarg1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/initlist25.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/inline-ns1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/inline-ns2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/inline-ns3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-conv.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-direct-init.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-init.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/linkage2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/rv-deduce.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/rv-reinterpret.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/rv-return.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing2.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing3.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing4.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/trailing5.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic95.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/variadic96.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/vt-40092.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/anonname1.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/icf.C create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/template-params-7.C create mode 100644 gcc/testsuite/g++.dg/eh/pr41819.C create mode 100644 gcc/testsuite/g++.dg/ext/always_inline-5.C create mode 100644 gcc/testsuite/g++.dg/ext/raw-string-1.C create mode 100644 gcc/testsuite/g++.dg/ext/raw-string-2.C create mode 100644 gcc/testsuite/g++.dg/ext/raw-string-3.C create mode 100644 gcc/testsuite/g++.dg/ext/raw-string-4.C create mode 100644 gcc/testsuite/g++.dg/ext/raw-string-5.C create mode 100644 gcc/testsuite/g++.dg/ext/raw-string-6.C create mode 100644 gcc/testsuite/g++.dg/ext/raw-string-7.C create mode 100644 gcc/testsuite/g++.dg/ext/sync-3.C create mode 100644 gcc/testsuite/g++.dg/ext/utf-badconcat2.C create mode 100644 gcc/testsuite/g++.dg/ext/utf-dflt2.C create mode 100644 gcc/testsuite/g++.dg/ext/utf8-1.C create mode 100644 gcc/testsuite/g++.dg/ext/utf8-2.C create mode 100644 gcc/testsuite/g++.dg/ext/visibility/namespace3.C create mode 100644 gcc/testsuite/g++.dg/gomp/pr41967.C create mode 100644 gcc/testsuite/g++.dg/init/static-init2.C create mode 100644 gcc/testsuite/g++.dg/init/synth2.C create mode 100644 gcc/testsuite/g++.dg/ipa/20090113-1.C create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-redecl2.C create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-redecl3.C create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-redecl4.C create mode 100644 gcc/testsuite/g++.dg/lookup/extern-c-redecl5.C create mode 100644 gcc/testsuite/g++.dg/lookup/koenig6.C create mode 100644 gcc/testsuite/g++.dg/lookup/koenig7.C create mode 100644 gcc/testsuite/g++.dg/lookup/using22.C create mode 100644 gcc/testsuite/g++.dg/lto/20080709_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080829_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080904_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080907_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080908-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080908-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080908-3_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080909-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080910-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080912-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080912_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080915_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080916_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080917_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080924_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20080926_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081008_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081022.h create mode 100644 gcc/testsuite/g++.dg/lto/20081022_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081022_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081023_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081109-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081109-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081109_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081109_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081118-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081118-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081118_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081118_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081119-1.h create mode 100644 gcc/testsuite/g++.dg/lto/20081119-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081119-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081119_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081119_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081120-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081120-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081120-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081120-2_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081123_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081123_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081125.h create mode 100644 gcc/testsuite/g++.dg/lto/20081125_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081125_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081127_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081127_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081203_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081203_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081204-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081204-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081204-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081204-2_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081209_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081209_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081211-1.h create mode 100644 gcc/testsuite/g++.dg/lto/20081211-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081211-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20081217-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081217-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081219_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20081219_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20090106_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090112_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090128_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090221_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090302_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090302_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20090303_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090311-1.h create mode 100644 gcc/testsuite/g++.dg/lto/20090311-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090311-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20090311_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090311_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20090312.h create mode 100644 gcc/testsuite/g++.dg/lto/20090312_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090312_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20090313_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090313_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20090315_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20090315_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20091002-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091002-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091002-3_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-2_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-3_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091004-3_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20091022-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091022-2_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091026-1_0.C create mode 100644 gcc/testsuite/g++.dg/lto/20091026-1_1.C create mode 100644 gcc/testsuite/g++.dg/lto/20091026-1_a.h create mode 100644 gcc/testsuite/g++.dg/lto/README create mode 100644 gcc/testsuite/g++.dg/lto/lto.exp create mode 100644 gcc/testsuite/g++.dg/lto/pr40818_0.C create mode 100644 gcc/testsuite/g++.dg/opt/eh5.C create mode 100644 gcc/testsuite/g++.dg/opt/inline16.C create mode 100644 gcc/testsuite/g++.dg/opt/thunk3-1.C create mode 100644 gcc/testsuite/g++.dg/opt/thunk4.C create mode 100644 gcc/testsuite/g++.dg/other/i386-7.C delete mode 100644 gcc/testsuite/g++.dg/other/linkage2.C create mode 100644 gcc/testsuite/g++.dg/other/offsetof6.C create mode 100644 gcc/testsuite/g++.dg/other/ptrmem10.C create mode 100644 gcc/testsuite/g++.dg/other/ptrmem11.C create mode 100644 gcc/testsuite/g++.dg/parse/eh-decl.C create mode 100644 gcc/testsuite/g++.dg/parse/error36.C create mode 100644 gcc/testsuite/g++.dg/plugin/pragma_plugin-test-1.C create mode 100644 gcc/testsuite/g++.dg/plugin/pragma_plugin.c create mode 100644 gcc/testsuite/g++.dg/rtti/typeid9.C create mode 100644 gcc/testsuite/g++.dg/template/explicit-args2.C create mode 100644 gcc/testsuite/g++.dg/template/explicit-args3.C create mode 100644 gcc/testsuite/g++.dg/template/overload11.C create mode 100644 gcc/testsuite/g++.dg/template/partial6.C create mode 100644 gcc/testsuite/g++.dg/template/scope3.C create mode 100644 gcc/testsuite/g++.dg/template/sfinae15.C create mode 100644 gcc/testsuite/g++.dg/template/sfinae16.C create mode 100644 gcc/testsuite/g++.dg/template/sizeof12.C create mode 100644 gcc/testsuite/g++.dg/torture/pr41680.C create mode 100644 gcc/testsuite/g++.dg/torture/pr41775.C create mode 100644 gcc/testsuite/g++.dg/tree-ssa/restrict1.C create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr40556.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr41182-1.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr41634.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr41646.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr41661.c create mode 100644 gcc/testsuite/gcc.c-torture/compile/pr41728.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr41750.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr41917.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr41919.c create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr41935.c create mode 100644 gcc/testsuite/gcc.dg/20081223-1.c create mode 100644 gcc/testsuite/gcc.dg/Wstrict-aliasing-bogus-vla-1.c create mode 100644 gcc/testsuite/gcc.dg/autopar/outer-1.c create mode 100644 gcc/testsuite/gcc.dg/autopar/outer-2.c create mode 100644 gcc/testsuite/gcc.dg/autopar/outer-3.c create mode 100644 gcc/testsuite/gcc.dg/autopar/outer-4.c create mode 100644 gcc/testsuite/gcc.dg/autopar/outer-5.c create mode 100644 gcc/testsuite/gcc.dg/autopar/outer-6.c create mode 100644 gcc/testsuite/gcc.dg/cleanup-13.c create mode 100644 gcc/testsuite/gcc.dg/cpp/include6.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/inline3.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-2.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-3.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-4.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-5.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41445-6.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41543.c create mode 100644 gcc/testsuite/gcc.dg/debug/dwarf2/pr41695.c create mode 100644 gcc/testsuite/gcc.dg/debug/pr41264-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/pr41343-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/pr41717.c create mode 100644 gcc/testsuite/gcc.dg/debug/pr41893-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/pr41893-2.c create mode 100644 gcc/testsuite/gcc.dg/debug/vta-1.c create mode 100644 gcc/testsuite/gcc.dg/debug/vta-2.c create mode 100644 gcc/testsuite/gcc.dg/debug/vta-3.c create mode 100644 gcc/testsuite/gcc.dg/guality/pr41447-1.c create mode 100644 gcc/testsuite/gcc.dg/guality/pr41616-1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20080908_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20080917_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20080924_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081024_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081109_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081111_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081111_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081112_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081112_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081115_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081115_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081115_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081118_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081118_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081118_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081120-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081120-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081120-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081120-2_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081125_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081125_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081126_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081201-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081201-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081201-1_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081201-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081201-2_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081202-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081202-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081202-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081202-2_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081204-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081204-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081204-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081210-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081212-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081222_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081222_0.h create mode 100644 gcc/testsuite/gcc.dg/lto/20081222_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081224_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20081224_0.h create mode 100644 gcc/testsuite/gcc.dg/lto/20081224_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090116_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090120_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090126-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090126-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090206-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090206-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090210_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090210_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090213_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090213_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218-2_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090218_3.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090219_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090312_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090312_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090313_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090706-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090706-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090717_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090717_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090729_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090729_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090812_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090812_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090914-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20090914-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091005-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091005-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091005-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091006-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091006-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091006-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091006-2_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091006-2_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091013-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091013-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091013-1_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091014-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091015-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091015-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091015-1_2.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091015-1_a.h create mode 100644 gcc/testsuite/gcc.dg/lto/20091015-1_b.h create mode 100644 gcc/testsuite/gcc.dg/lto/20091016-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091016-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091016-1_a.h create mode 100644 gcc/testsuite/gcc.dg/lto/20091017-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091017-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091020-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091020-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091020-2_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091020-2_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091020-3_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091027-1_0.c create mode 100644 gcc/testsuite/gcc.dg/lto/20091027-1_1.c create mode 100644 gcc/testsuite/gcc.dg/lto/README create mode 100644 gcc/testsuite/gcc.dg/lto/lto.exp create mode 100644 gcc/testsuite/gcc.dg/noncompile/pr40033-1.c create mode 100644 gcc/testsuite/gcc.dg/pr41340.c create mode 100644 gcc/testsuite/gcc.dg/pr41345.c create mode 100644 gcc/testsuite/gcc.dg/pr41573.c create mode 100644 gcc/testsuite/gcc.dg/pr41574.c create mode 100644 gcc/testsuite/gcc.dg/pr41762.c create mode 100644 gcc/testsuite/gcc.dg/pr41783.c create mode 100644 gcc/testsuite/gcc.dg/pr41837.c create mode 100644 gcc/testsuite/gcc.dg/pr41841.c create mode 100644 gcc/testsuite/gcc.dg/pr41842.c create mode 100644 gcc/testsuite/gcc.dg/pr41935.c create mode 100644 gcc/testsuite/gcc.dg/pr41963.c create mode 100644 gcc/testsuite/gcc.dg/raw-string-1.c create mode 100644 gcc/testsuite/gcc.dg/raw-string-2.c create mode 100644 gcc/testsuite/gcc.dg/raw-string-3.c create mode 100644 gcc/testsuite/gcc.dg/raw-string-4.c create mode 100644 gcc/testsuite/gcc.dg/raw-string-5.c create mode 100644 gcc/testsuite/gcc.dg/raw-string-6.c create mode 100644 gcc/testsuite/gcc.dg/raw-string-7.c create mode 100644 gcc/testsuite/gcc.dg/tls/pie-1.c create mode 100644 gcc/testsuite/gcc.dg/torture/pr23821.c create mode 100644 gcc/testsuite/gcc.dg/torture/pr26515.c create mode 100644 gcc/testsuite/gcc.dg/torture/pr38948.c create mode 100644 gcc/testsuite/gcc.dg/torture/pr41555.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr41497.c delete mode 100644 gcc/testsuite/gcc.dg/tree-ssa/restrict-1.c delete mode 100644 gcc/testsuite/gcc.dg/tree-ssa/restrict-2.c delete mode 100644 gcc/testsuite/gcc.dg/tree-ssa/restrict-4.c create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-pre-26.c create mode 100644 gcc/testsuite/gcc.dg/utf-badconcat2.c create mode 100644 gcc/testsuite/gcc.dg/utf-dflt2.c create mode 100644 gcc/testsuite/gcc.dg/utf8-1.c create mode 100644 gcc/testsuite/gcc.dg/utf8-2.c create mode 100644 gcc/testsuite/gcc.target/arm/neon-thumb2-move.c create mode 100644 gcc/testsuite/gcc.target/arm/neon/vfp-shift-a2t2.c create mode 100644 gcc/testsuite/gcc.target/arm/pr40835.c create mode 100644 gcc/testsuite/gcc.target/arm/thumb-bitfld1.c create mode 100644 gcc/testsuite/gcc.target/arm/thumb-branch1.c create mode 100644 gcc/testsuite/gcc.target/arm/thumb-ltu.c create mode 100644 gcc/testsuite/gcc.target/avr/torture/pr41885.c create mode 100644 gcc/testsuite/gcc.target/i386/brokensqrt.c delete mode 100644 gcc/testsuite/gcc.target/i386/cold-attribute-4.s create mode 100644 gcc/testsuite/gcc.target/i386/incoming-10.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-11.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-12.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-13.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-14.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-15.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-6.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-7.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-8.c create mode 100644 gcc/testsuite/gcc.target/i386/incoming-9.c create mode 100644 gcc/testsuite/gcc.target/i386/ms_hook_prologue.c create mode 100644 gcc/testsuite/gcc.target/i386/pr37843-4.c create mode 100644 gcc/testsuite/gcc.target/i386/pr41900.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-check.h create mode 100644 gcc/testsuite/gcc.target/i386/xop-haddX.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-hadduX.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-hsubX.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-imul32widen-vector.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-imul64-vector.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-pcmov.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-pcmov2.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-rotate1-vector.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-rotate2-vector.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-rotate3-vector.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-shift1-vector.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-shift2-vector.c create mode 100644 gcc/testsuite/gcc.target/i386/xop-shift3-vector.c create mode 100644 gcc/testsuite/gcc.target/m68k/pr41302.c create mode 100644 gcc/testsuite/gcc.target/mips/mmcount-ra-address-1.c create mode 100644 gcc/testsuite/gcc.target/mips/mmcount-ra-address-2.c create mode 100644 gcc/testsuite/gcc.target/mips/mmcount-ra-address-3.c create mode 100644 gcc/testsuite/gcc.target/mips/mult-1.c create mode 100644 gcc/testsuite/gcc.target/mips/truncate-6.c create mode 100644 gcc/testsuite/gcc.target/powerpc/altivec-33.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-1.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-2.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-3.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-4.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-5.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-6.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-7.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vectorize-8.c create mode 100644 gcc/testsuite/gcc.target/powerpc/vsx-vrsave.c create mode 100644 gcc/testsuite/gcc.target/rx/builtins.c create mode 100644 gcc/testsuite/gcc.target/rx/i272091.c create mode 100644 gcc/testsuite/gcc.target/rx/interrupts.c create mode 100644 gcc/testsuite/gcc.target/rx/packed-struct.c create mode 100644 gcc/testsuite/gcc.target/rx/rx-abi-function-tests.c create mode 100644 gcc/testsuite/gcc.target/rx/rx.exp create mode 100644 gcc/testsuite/gcc.target/rx/zero-width-bitfield.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/cache1.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/cast1.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/cast2.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/compile1.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/compile2.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/cppdefine.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/ea.exp create mode 100644 gcc/testsuite/gcc.target/spu/ea/errors1.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/errors2.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/execute1.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/execute2.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/execute3.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/ops1.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/ops2.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/options1.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/pr41857.c create mode 100644 gcc/testsuite/gcc.target/spu/ea/test-sizes.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-1.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-2.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-3.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-4.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-5.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-6.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-7.c delete mode 100644 gcc/testsuite/gcc.target/vsx-vectorize-8.c create mode 100644 gcc/testsuite/gfortran.dg/allocatable_scalar_4.f90 create mode 100644 gcc/testsuite/gfortran.dg/associated_target_3.f90 create mode 100644 gcc/testsuite/gfortran.dg/assumed_charlen_function_6.f90 create mode 100644 gcc/testsuite/gfortran.dg/auto_dealloc_1.f90 create mode 100644 gcc/testsuite/gfortran.dg/class_10.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_11.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_12.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_4a.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_4b.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_4c.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_4d.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_5.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_6.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_7.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_8.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_9.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_allocate_2.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_allocate_3.f03 create mode 100644 gcc/testsuite/gfortran.dg/class_allocate_4.f03 create mode 100644 gcc/testsuite/gfortran.dg/complex_intrinsic_8.f90 create mode 100644 gcc/testsuite/gfortran.dg/dynamic_dispatch_1.f03 create mode 100644 gcc/testsuite/gfortran.dg/dynamic_dispatch_2.f03 create mode 100644 gcc/testsuite/gfortran.dg/dynamic_dispatch_3.f03 create mode 100644 gcc/testsuite/gfortran.dg/dynamic_dispatch_4.f03 create mode 100644 gcc/testsuite/gfortran.dg/dynamic_dispatch_5.f03 create mode 100644 gcc/testsuite/gfortran.dg/equiv_8.f90 create mode 100644 gcc/testsuite/gfortran.dg/extends_8.f03 create mode 100644 gcc/testsuite/gfortran.dg/fmt_error_10.f create mode 100644 gcc/testsuite/gfortran.dg/fmt_error_9.f create mode 100644 gcc/testsuite/gfortran.dg/goto_6.f create mode 100644 gcc/testsuite/gfortran.dg/goto_7.f create mode 100644 gcc/testsuite/gfortran.dg/goto_8.f90 create mode 100644 gcc/testsuite/gfortran.dg/guality/arg1.f90 create mode 100644 gcc/testsuite/gfortran.dg/guality/guality.exp create mode 100644 gcc/testsuite/gfortran.dg/guality/pr41558.f90 create mode 100644 gcc/testsuite/gfortran.dg/intent_out_6.f90 create mode 100644 gcc/testsuite/gfortran.dg/interface_abstract_4.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/20091015-1_0.f create mode 100644 gcc/testsuite/gfortran.dg/lto/20091015-1_1.f create mode 100644 gcc/testsuite/gfortran.dg/lto/20091015-1_2.f create mode 100644 gcc/testsuite/gfortran.dg/lto/20091016-1_0.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/20091028-1_0.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/20091028-1_1.c create mode 100644 gcc/testsuite/gfortran.dg/lto/20091028-2_0.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/20091028-2_1.c create mode 100644 gcc/testsuite/gfortran.dg/lto/lto.exp create mode 100644 gcc/testsuite/gfortran.dg/lto/pr40724_0.f create mode 100644 gcc/testsuite/gfortran.dg/lto/pr40724_1.f create mode 100644 gcc/testsuite/gfortran.dg/lto/pr40725_0.f03 create mode 100644 gcc/testsuite/gfortran.dg/lto/pr40725_1.c create mode 100644 gcc/testsuite/gfortran.dg/lto/pr41069_0.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/pr41069_1.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/pr41069_2.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/pr41521_0.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/pr41521_1.f90 create mode 100644 gcc/testsuite/gfortran.dg/lto/pr41764_0.f create mode 100644 gcc/testsuite/gfortran.dg/missing_optional_dummy_6.f90 create mode 100644 gcc/testsuite/gfortran.dg/round_2.f03 create mode 100644 gcc/testsuite/gfortran.dg/select_type_5.f03 create mode 100644 gcc/testsuite/gfortran.dg/select_type_6.f03 create mode 100644 gcc/testsuite/gfortran.dg/select_type_7.f03 create mode 100644 gcc/testsuite/gfortran.dg/transfer_intrinsic_3.f90 create mode 100644 gcc/testsuite/gfortran.fortran-torture/compile/pr41654.f90 create mode 100644 gcc/testsuite/gnat.dg/aggr11.adb create mode 100644 gcc/testsuite/gnat.dg/aggr11_pkg.ads create mode 100644 gcc/testsuite/gnat.dg/discr21.adb create mode 100644 gcc/testsuite/gnat.dg/discr21.ads create mode 100644 gcc/testsuite/gnat.dg/discr21_pkg.ads create mode 100644 gcc/testsuite/gnat.dg/discr22.adb create mode 100644 gcc/testsuite/gnat.dg/loop_optimization7.adb create mode 100644 gcc/testsuite/gnat.dg/loop_optimization7.ads create mode 100644 gcc/testsuite/gnat.dg/loop_optimization7_pkg.ads delete mode 100644 gcc/testsuite/gnat.dg/nested_proc.adb create mode 100644 gcc/testsuite/gnat.dg/nested_proc1.adb create mode 100644 gcc/testsuite/gnat.dg/nested_proc2.adb create mode 100644 gcc/testsuite/gnat.dg/noreturn1.adb create mode 100644 gcc/testsuite/gnat.dg/noreturn1.ads create mode 100644 gcc/testsuite/gnat.dg/noreturn2.adb create mode 100644 gcc/testsuite/gnat.dg/noreturn2.ads create mode 100644 gcc/testsuite/gnat.dg/null_pointer_deref1.adb create mode 100644 gcc/testsuite/gnat.dg/null_pointer_deref2.adb create mode 100644 gcc/testsuite/gnat.dg/opt3.adb create mode 100644 gcc/testsuite/gnat.dg/opt3_pkg.ads create mode 100644 gcc/testsuite/gnat.dg/opt4.adb create mode 100644 gcc/testsuite/gnat.dg/opt5.adb create mode 100644 gcc/testsuite/gnat.dg/pack14.adb create mode 100644 gcc/testsuite/gnat.dg/slice8.adb create mode 100644 gcc/testsuite/gnat.dg/slice8_pkg1.ads create mode 100644 gcc/testsuite/gnat.dg/slice8_pkg2.ads create mode 100644 gcc/testsuite/gnat.dg/slice8_pkg3.adb create mode 100644 gcc/testsuite/gnat.dg/slice8_pkg3.ads create mode 100644 gcc/testsuite/gnat.dg/specs/import_abstract.ads create mode 100644 gcc/testsuite/gnat.dg/specs/pack4.ads create mode 100644 gcc/testsuite/gnat.dg/specs/pack5.ads create mode 100644 gcc/testsuite/gnat.dg/specs/rep_clause4.ads create mode 100644 gcc/testsuite/gnat.dg/stack_check1.adb create mode 100644 gcc/testsuite/gnat.dg/stack_check2.adb create mode 100644 gcc/testsuite/gnat.dg/timer_cancel.adb create mode 100644 gcc/testsuite/gnat.dg/unchecked_convert4.adb create mode 100644 gcc/testsuite/lib/gcc-gdb-test.exp create mode 100644 gcc/testsuite/lib/lto.exp (limited to 'gcc') diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 7263e90833f..d0df7de35ed 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,7 +1,3893 @@ +2009-11-06 Michael Matz + + PR middle-end/41963 + * tree-ssa-math-opts.c (execute_cse_reciprocals): Check all uses + of a potential reciprocal to really be reciprocals. + +2009-11-06 Jakub Jelinek + + * config/i386/x86intrin.h: Include fma4intrin.h, xopintrin.h and + lwpintrin.h after immintrin.h. + * config/i386/fma4intrin.h (__v8sf, __v4df, __m256, __m256d): Remove + typedefs. + + PR middle-end/41935 + * c-common.c (fold_offsetof_1) : Don't crash for VLAs + or non-constant index, allow index one past the last element and + allow exceeding array bound in arrays that might be used as flexible + array members. + +2009-11-05 Richard Henderson + + * config/i386/ia32intrin.h: Protect CRC32 builtins with __SSE4_2__. + +2009-11-05 Paul Brook + + * config/arm/arm.c (arm_fp_model, arm_fpu_arch, arm_fpu_tune): Remove. + (arm_fpu_desc): New. + (all_fpus): Add FPU details. + (fp_model_for_fpu): Remove. + (arm_override_options): Set and use arm_fpu_desc and arm_fpu_attr. + (arm_output_epilogue, arm_save_coproc_regs): Use TARGET_FPA_EMU2. + (arm_file_start): Use arm_fpu_desc. + * config/arm/arm.h (TARGET_FPA, TARGET_MAVERICK, TARGET_VFP, + TARGET_VFPD32, TARGET_VFP3, TARGET_NEON_FP16, TARGET_NEON): Use + arm_fpu_desc. + (TARGET_FPA_EMU2): Define. + (arm_fp_model, fputype, arm_fpu_tune): Remove. + (vfp_reg_type, arm_fpu_desc): New. + * config/arm/arm.md (attr fpu): Simplify. + * config/arm/fpa.md (movxf_fpa): Use TARGET_FPA_EMU2. + * config/arm/linux-elf.h (FPUTYPE_DEFAULT): Use string value. + * config/arm/bpabi.h (FPUTYPE_DEFAULT): Use string value. + * config/arm/netbsd-elf.h (FPUTYPE_DEFAULT): Use string value. + * config/arm/vxworks.h (FPUTYPE_DEFAULT): Use string value. + +2009-11-05 Michael Matz + + * config/i386/i386.c (ix86_builtin_reciprocal): Remove dependency + on TARGET_RECIP. + * doc/invoke.texi (-mrecip): Clarify that we don't need -mrecip + for 1/sqrtf. + +2009-11-04 Jason Merrill + + PR c++/36912 + * varasm.c (initializer_constant_valid_p): A PLUS_EXPR + or MINUS_EXPR of REAL_TYPE is not a valid constant initializer. + (output_constant): Avoid crash after error. + +2009-11-05 Martin Jambor + + * tree-sra.c (struct access): Changed comment of next_sibling field. + (analyze_modified_params): Loop over accesses of a group rather than + over all with the ame base, pass a common bitmap to + walk_aliased_vdefs. + (unmodified_by_ref_scalar_representative): Build link lists of + accesses of a group. + (splice_param_accesses): Likewise. + +2009-11-04 Kenneth Zadeck + + * df-scan.c (df-uses-record): Add case zero_extract of mem. + +2009-11-04 Eric Botcazou + + PR target/10127 + PR ada/20548 + * config/i386/i386.md (probe_stack): New expander. + (logical operation peepholes): Do not split stack checking probes. + +2009-11-04 Harsha Jagasia + Dwarakanath Rajagopal + + * doc/invoke.texi (-mlwp): Add documentation. + * doc/extend.texi (x86 intrinsics): Add LWP intrinsics. + * config.gcc (i[34567]86-*-*): Include lwpintrin.h. + (x86_64-*-*): Ditto. + * config/i386/lwpintrin.h: New file, provide x86 compiler + intrinisics for LWP. + * config/i386/cpuid.h (bit_LWP): Define LWP bit. + * config/i386/x86intrin.h: Add LWP check and lwpintrin.h. + * config/i386/i386-c.c (ix86_target_macros_internal): Check + ISA_FLAG for LWP. + * config/i386/i386.h (TARGET_LWP): New macro for LWP. + * config/i386/i386.opt (-mlwp): New switch for LWP support. + * config/i386/i386.c (OPTION_MASK_ISA_LWP_SET): New. + (OPTION_MASK_ISA_LWP_UNSET): New. + (ix86_handle_option): Handle -mlwp. + (isa_opts): Handle -mlwp. + (enum pta_flags): Add PTA_LWP. + (override_options): Add LWP support. + (IX86_BUILTIN_LLWPCB16): New for LWP intrinsic. + (IX86_BUILTIN_LLWPCB32): Ditto. + (IX86_BUILTIN_LLWPCB64): Ditto. + (IX86_BUILTIN_SLWPCB16): Ditto. + (IX86_BUILTIN_SLWPCB32): Ditto. + (IX86_BUILTIN_SLWPCB64): Ditto. + (IX86_BUILTIN_LWPVAL16): Ditto. + (IX86_BUILTIN_LWPVAL32): Ditto. + (IX86_BUILTIN_LWPVAL64): Ditto. + (IX86_BUILTIN_LWPINS16): Ditto. + (IX86_BUILTIN_LWPINS32): Ditto. + (IX86_BUILTIN_LWPINS64): Ditto. + (enum ix86_special_builtin_type): Add LWP intrinsic support. + (builtin_description): Ditto. + (ix86_init_mmx_sse_builtins): Ditto. + (ix86_expand_special_args_builtin): Ditto. + * config/i386/i386.md (UNSPEC_LLWP_INTRINSIC): Add new UNSPEC for + LWP support. + (UNSPEC_SLWP_INTRINSIC): Ditto. + (UNSPECV_LWPVAL_INTRINSIC): Ditto. + (UNSPECV_LWPINS_INTRINSIC): Ditto. + (lwp_llwpcbhi1): New lwp pattern. + (lwp_llwpcbsi1): Ditto. + (lwp_llwpcbdi1): Ditto. + (lwp_slwpcbhi1): Ditto. + (lwp_slwpcbsi1): Ditto. + (lwp_slwpcbdi1): Ditto. + (lwp_lwpvalhi3): Ditto. + (lwp_lwpvalsi3): Ditto. + (lwp_lwpvaldi3): Ditto. + (lwp_lwpinshi3): Ditto. + (lwp_lwpinssi3): Ditto. + (lwp_lwpinsdi3): Ditto. + +2009-11-04 Andrew Pinski + Trevor Smigiel + + PR rtl-opt/41833 + * simplify-rtx.c (simplify_binary_operation_1): Simplify vec_select of + a vec_duplicate. + +2009-11-04 Richard Guenther + Rafael Avila de Espindola + + * gcc.c (process_command): Handle arguments name@offset. + +2009-11-04 Harsha Jagasia + Dwarakanath Rajagopal + + * config.gcc (i[34567]86-*-*): Include xopintrin.h. + (x86_64-*-*): Ditto. + * config/i386/xopintrin.h: New file, provide common x86 compiler + intrinisics for XOP. + * config/i386/cpuid.h (bit_XOP): Define XOP bit. + * config/i386/x86intrin.h: Add XOP check and xopintrin.h. + * config/i386/i386-c.c(ix86_target_macros_internal): Check + ISA_FLAG for XOP. + * config/i386/i386.h(TARGET_XOP): New macro for XOP. + * config/i386/i386.opt (-mxop): New switch for XOP support. + * config/i386/i386.md (UNSPEC_XOP_UNSIGNED_CMP) + (UNSPEC_XOP_TRUEFALSE) + (UNSPEC_XOP_PERMUTE) + (UNSPEC_FRCZ): Add new UNSPEC for XOP support. + (PPERM_*): New constants for vpperm instruction. + (xop_pcmov_): Add XOP conditional mov instructions. + * config/i386/i386.c (OPTION_MASK_ISA_XOP_SET): New. + (OPTION_MASK_ISA_XOP_UNSET): New. + (OPTION_MASK_ISA_XOP_UNSET): Change definition to + depend on XOP. + (ix86_handle_option): Handle -mxop. + (isa_opts): Handle -mxop. + (enum pta_flags): Add PTA_XOP. + (override_options): Add XOP support. + (print_operand): Add code for XOP compare instructions. + (ix86_expand_sse_movcc): Extend for XOP conditional move instruction. + (ix86_expand_int_vcond): Extend for XOP compare instruction. + + (IX86_BUILTIN_VPCMOV): New for XOP intrinsic. + (IX86_BUILTIN_VPCMOV_V2DI): Ditto. + (IX86_BUILTIN_VPCMOV_V4SI): Ditto. + (IX86_BUILTIN_VPCMOV_V8HI): Ditto. + (IX86_BUILTIN_VPCMOV_V16QI): Ditto. + (IX86_BUILTIN_VPCMOV_V4SF): Ditto. + (IX86_BUILTIN_VPCMOV_V2DF): Ditto. + + (IX86_BUILTIN_VPCMOV256): Ditto. + (IX86_BUILTIN_VPCMOV_V4DI256): Ditto. + (IX86_BUILTIN_VPCMOV_V8SI256): Ditto. + (IX86_BUILTIN_VPCMOV_V16HI256): Ditto. + (IX86_BUILTIN_VPCMOV_V32QI256): Ditto. + (IX86_BUILTIN_VPCMOV_V8SF256): Ditto. + (IX86_BUILTIN_VPCMOV_V4DF256): Ditto. + + (IX86_BUILTIN_VPPERM): Ditto. + + (IX86_BUILTIN_VPMACSSWW): Ditto. + (IX86_BUILTIN_VPMACSWW): Ditto. + (IX86_BUILTIN_VPMACSSWD): Ditto. + (IX86_BUILTIN_VPMACSWD): Ditto. + (IX86_BUILTIN_VPMACSSDD): Ditto. + (IX86_BUILTIN_VPMACSDD): Ditto. + (IX86_BUILTIN_VPMACSSDQL): Ditto. + (IX86_BUILTIN_VPMACSSDQH): Ditto. + (IX86_BUILTIN_VPMACSDQL): Ditto. + (IX86_BUILTIN_VPMACSDQH): Ditto. + (IX86_BUILTIN_VPMADCSSWD): Ditto. + (IX86_BUILTIN_VPMADCSWD): Ditto. + + (IX86_BUILTIN_VPHADDBW): Ditto. + (IX86_BUILTIN_VPHADDBD): Ditto. + (IX86_BUILTIN_VPHADDBQ): Ditto. + (IX86_BUILTIN_VPHADDWD): Ditto. + (IX86_BUILTIN_VPHADDWQ): Ditto. + (IX86_BUILTIN_VPHADDDQ): Ditto. + (IX86_BUILTIN_VPHADDUBW): Ditto. + (IX86_BUILTIN_VPHADDUBD): Ditto. + (IX86_BUILTIN_VPHADDUBQ): Ditto. + (IX86_BUILTIN_VPHADDUWD): Ditto. + (IX86_BUILTIN_VPHADDUWQ): Ditto. + (IX86_BUILTIN_VPHADDUDQ): Ditto. + (IX86_BUILTIN_VPHSUBBW): Ditto. + (IX86_BUILTIN_VPHSUBWD): Ditto. + (IX86_BUILTIN_VPHSUBDQ): Ditto. + + (IX86_BUILTIN_VPROTB): Ditto. + (IX86_BUILTIN_VPROTW): Ditto. + (IX86_BUILTIN_VPROTD): Ditto. + (IX86_BUILTIN_VPROTQ): Ditto. + (IX86_BUILTIN_VPROTB_IMM): Ditto. + (IX86_BUILTIN_VPROTW_IMM): Ditto. + (IX86_BUILTIN_VPROTD_IMM): Ditto. + (IX86_BUILTIN_VPROTQ_IMM): Ditto. + + (IX86_BUILTIN_VPSHLB): Ditto. + (IX86_BUILTIN_VPSHLW): Ditto. + (IX86_BUILTIN_VPSHLD): Ditto. + (IX86_BUILTIN_VPSHLQ): Ditto. + (IX86_BUILTIN_VPSHAB): Ditto. + (IX86_BUILTIN_VPSHAW): Ditto. + (IX86_BUILTIN_VPSHAD): Ditto. + (IX86_BUILTIN_VPSHAQ): Ditto. + + (IX86_BUILTIN_VFRCZSS): Ditto. + (IX86_BUILTIN_VFRCZSD): Ditto. + (IX86_BUILTIN_VFRCZPS): Ditto. + (IX86_BUILTIN_VFRCZPD): Ditto. + (IX86_BUILTIN_VFRCZPS256): Ditto. + (IX86_BUILTIN_VFRCZPD256): Ditto. + + (IX86_BUILTIN_VPCOMEQUB): Ditto. + (IX86_BUILTIN_VPCOMNEUB): Ditto. + (IX86_BUILTIN_VPCOMLTUB): Ditto. + (IX86_BUILTIN_VPCOMLEUB): Ditto. + (IX86_BUILTIN_VPCOMGTUB): Ditto. + (IX86_BUILTIN_VPCOMGEUB): Ditto. + (IX86_BUILTIN_VPCOMFALSEUB): Ditto. + (IX86_BUILTIN_VPCOMTRUEUB): Ditto. + + (IX86_BUILTIN_VPCOMEQUW): Ditto. + (IX86_BUILTIN_VPCOMNEUW): Ditto. + (IX86_BUILTIN_VPCOMLTUW): Ditto. + (IX86_BUILTIN_VPCOMLEUW): Ditto. + (IX86_BUILTIN_VPCOMGTUW): Ditto. + (IX86_BUILTIN_VPCOMGEUW): Ditto. + (IX86_BUILTIN_VPCOMFALSEUW): Ditto. + (IX86_BUILTIN_VPCOMTRUEUW): Ditto. + + (IX86_BUILTIN_VPCOMEQUD): Ditto. + (IX86_BUILTIN_VPCOMNEUD): Ditto. + (IX86_BUILTIN_VPCOMLTUD): Ditto. + (IX86_BUILTIN_VPCOMLEUD): Ditto. + (IX86_BUILTIN_VPCOMGTUD): Ditto. + (IX86_BUILTIN_VPCOMGEUD): Ditto. + (IX86_BUILTIN_VPCOMFALSEUD): Ditto. + (IX86_BUILTIN_VPCOMTRUEUD): Ditto. + + (IX86_BUILTIN_VPCOMEQUQ): Ditto. + (IX86_BUILTIN_VPCOMNEUQ): Ditto. + (IX86_BUILTIN_VPCOMLTUQ): Ditto. + (IX86_BUILTIN_VPCOMLEUQ): Ditto. + (IX86_BUILTIN_VPCOMGTUQ): Ditto. + (IX86_BUILTIN_VPCOMGEUQ): Ditto. + (IX86_BUILTIN_VPCOMFALSEUQ): Ditto. + (IX86_BUILTIN_VPCOMTRUEUQ): Ditto. + + (IX86_BUILTIN_VPCOMEQB): Ditto. + (IX86_BUILTIN_VPCOMNEB): Ditto. + (IX86_BUILTIN_VPCOMLTB): Ditto. + (IX86_BUILTIN_VPCOMLEB): Ditto. + (IX86_BUILTIN_VPCOMGTB): Ditto. + (IX86_BUILTIN_VPCOMGEB): Ditto. + (IX86_BUILTIN_VPCOMFALSEB): Ditto. + (IX86_BUILTIN_VPCOMTRUEB): Ditto. + + (IX86_BUILTIN_VPCOMEQW): Ditto. + (IX86_BUILTIN_VPCOMNEW): Ditto. + (IX86_BUILTIN_VPCOMLTW): Ditto. + (IX86_BUILTIN_VPCOMLEW): Ditto. + (IX86_BUILTIN_VPCOMGTW): Ditto. + (IX86_BUILTIN_VPCOMGEW): Ditto. + (IX86_BUILTIN_VPCOMFALSEW): Ditto. + (IX86_BUILTIN_VPCOMTRUEW): Ditto. + + (IX86_BUILTIN_VPCOMEQD): Ditto. + (IX86_BUILTIN_VPCOMNED): Ditto. + (IX86_BUILTIN_VPCOMLTD): Ditto. + (IX86_BUILTIN_VPCOMLED): Ditto. + (IX86_BUILTIN_VPCOMGTD): Ditto. + (IX86_BUILTIN_VPCOMGED): Ditto. + (IX86_BUILTIN_VPCOMFALSED): Ditto. + (IX86_BUILTIN_VPCOMTRUED): Ditto. + + (IX86_BUILTIN_VPCOMEQQ): Ditto. + (IX86_BUILTIN_VPCOMNEQ): Ditto. + (IX86_BUILTIN_VPCOMLTQ): Ditto. + (IX86_BUILTIN_VPCOMLEQ): Ditto. + (IX86_BUILTIN_VPCOMGTQ): Ditto. + (IX86_BUILTIN_VPCOMGEQ): Ditto. + (IX86_BUILTIN_VPCOMFALSEQ): Ditto. + (IX86_BUILTIN_VPCOMTRUEQ): Ditto. + + (enum multi_arg_type): New enum for describing the various XOP + intrinsic argument types. + (bdesc_multi_arg): New table for XOP intrinsics. + (ix86_init_mmx_sse_builtins): Add XOP intrinsic support. + (ix86_expand_multi_arg_builtin): New function for creating XOP + intrinsics. + + * config/i386/sse.md (sserotatemax): New mode attribute for XOP. + (xop_pmacsww): Ditto. + (xop_pmacssww): Ditto. + (xop_pmacsdd): Ditto. + (xop_pmacssdd): Ditto. + (xop_pmacssdql): Ditto. + (xop_pmacssdqh): Ditto. + (xop_pmacsdql): Ditto. + (xop_pmacsdql_mem): Ditto. + (xop_mulv2div2di3_low): Ditto. + (xop_pmacsdqh): Ditto. + (xop_pmacsdqh_mem): Ditto. + (xop_mulv2div2di3_high): Ditto. + (xop_pmacsswd): Ditto. + (xop_pmacswd): Ditto. + (xop_pmadcsswd): Ditto. + (xop_pmadcswd): Ditto. + (xop_pcmov_): Ditto. + (xop_pcmov_)256: Ditto. + (xop_phaddbw): Ditto. + (xop_phaddbd): Ditto. + (xop_phaddbq): Ditto. + (xop_phaddwd): Ditto. + (xop_phaddwq): Ditto. + (xop_phadddq): Ditto. + (xop_phaddubw): Ditto. + (xop_phaddubd): Ditto. + (xop_phaddubq): Ditto. + (xop_phadduwd): Ditto. + (xop_phadduwq): Ditto. + (xop_phaddudq): Ditto. + (xop_phsubbw): Ditto. + (xop_phsubwd): Ditto. + (xop_phsubdq): Ditto. + (xop_pperm): Ditto. + (rotl3): Ditto. + (rotr3): Ditto. + (xop_rotl3): Ditto. + (xop_rotr3): Ditto. + (vrotr3): Ditto. + (vrotl3): Ditto. + (xop_vrotl3): Ditto. + (vlshr3): Ditto. + (vashr3): Ditto. + (vashl3 + (xop_ashl3): Ditto. + (xop_lshl3): Ditto. + (ashlv16qi3): Ditto. + (lshlv16qi3): Ditto. + (ashrv16qi3): Ditto. + (ashrv2di3): Ditto. + (xop_frcz2): Ditto. + (xop_vmfrcz2): Ditto. + (xop_frcz2256): Ditto. + (xop_maskcmp3): Ditto. + (xop_maskcmp_uns3): Ditto. + (xop_maskcmp_uns23): Ditto. + (xop_pcom_tf3): Ditto. + + * doc/invoke.texi (-mxop): Add documentation. + * doc/extend.texi (x86 intrinsics): Add XOP intrinsics. + +2009-11-03 Mark Mitchell + + PR driver/11810 + * gcc.c (SWITCHES_NEED_SPACES): Define to "o". + * config/alpha/osf.h (SWITCHES_NEED_SPACES): Remove here. + * config/mips/iris.h (SWITCHES_NEED_SPACES): Remove here. + +2009-11-04 Richard Earnshaw + + PR target/40835 + * arm.md (peephole2 patterns for move and compare): New. + +2009-11-04 Nick Clifton + + * defaults.h (CONSTANT_ADDRESS_P): Provide a default definition. + Make sure that it does not allow CONST_DOUBLEs. + * doc/tm.texi (CONSTANT_ADDRESS_P): Update description. + * config/avr/avr.h (CONSTANT_ADDRESS_P): Delete. + * config/bfin/bfin.h (CONSTANT_ADDRESS_P): Delete. + * config/cris/cris.h (CONSTANT_ADDRESS_P): Delete. + * config/fr30/fr30.h (CONSTANT_ADDRESS_P): Delete. + * config/frv/frv.h (CONSTANT_ADDRESS_P): Delete. + * config/m32c/m32c.h (CONSTANT_ADDRESS_P): Delete. + * config/m68hc11/m68hc11.h (CONSTANT_ADDRESS_P): Delete. + * config/mep/mep.h (CONSTANT_ADDRESS_P): Delete. + * config/mn10300/mn10300.h (CONSTANT_ADDRESS_P): Delete. + * config/moxie/moxie.h (CONSTANT_ADDRESS_P): Delete. + * config/pdp11/pdp11.h (CONSTANT_ADDRESS_P): Delete. + * config/picochip/picochip.h (CONSTANT_ADDRESS_P): Delete. + * config/score/score.h (CONSTANT_ADDRESS_P): Delete. + * config/stormy16/stormy16.h (CONSTANT_ADDRESS_P): Delete. + +2009-11-04 Richard Guenther + + PR tree-optimization/41919 + * tree-vrp.c (test_for_singularity): Properly compare values. + +2009-11-04 Revital Eres + + * tree-vect-data-refs.c (vect_enhance_data_refs_alignment): + Consider peeling for alignment only for stores and remove + redundant assignment. + +2009-11-04 Maxim Kuvyrkov + + PR target/41302 + * config/m68k/m68k.c (m68k_reg_present_p): New static function. + (m68k_ok_for_sibcall_p): Handle different result return locations. + +2009-11-04 Richard Guenther + + * c-opts.c (c_common_post_options): Move LTO option processing + code ... + * opts.c (decode_options): ... here. + +2009-11-04 Jakub Jelinek + + * c-common.c (fold_offsetof_1): Use %wd instead of + HOST_WIDE_INT_PRINT_DEC. + +2009-11-04 Maciej W. Rozycki + + * config/vax/linux.h (TARGET_OS_CPP_BUILTINS): Don't define + __pic__ or __PIC__. + +2009-11-04 Maciej W. Rozycki + + * config.gcc (vax-*-linux*): Keep the original contents of + tmake_file while adding vax/t-linux. + +2009-11-03 Eric Botcazou + + PR target/10127 + PR ada/20548 + * expr.h (STACK_CHECK_PROBE_INTERVAL): Delete. + (STACK_CHECK_PROBE_INTERVAL_EXP): New macro. + (STACK_CHECK_MOVING_SP): Likewise. + * system.h (STACK_CHECK_PROBE_INTERVAL): Poison it. + * doc/tm.texi (Stack Checking): Delete STACK_CHECK_PROBE_INTERVAL. + Document STACK_CHECK_PROBE_INTERVAL_EXP and STACK_CHECK_MOVING_SP. + * doc/md.texi (Standard Pattern Names): Tweak entry of CHECK_STACK. + Document PROBE_STACK. + * explow.c (anti_adjust_stack_and_probe): New function. + (allocate_dynamic_stack_space): Do not directly allocate space if + STACK_CHECK_MOVING_SP, instead invoke above function. + (emit_stack_probe): Handle probe_stack insn. + (PROBE_INTERVAL): New macro. + (STACK_GROW_OPTAB): Likewise. + (STACK_GROW_OFF): Likewise. + (probe_stack_range): Use Pmode and memory_address consistently. Fix + loop condition in the small constant case. Rewrite in the general + case to be immune to wraparounds. Make sure the address of probes + is valid. Try to use [base + disp] addressing mode if possible. + * ira.c (setup_eliminable_regset): Set frame_pointer_needed if stack + checking is enabled and STACK_CHECK_MOVING_SP. + * rtlanal.c (may_trap_p_1) : If stack checking is enabled, + return 1 for volatile references to the stack pointer. + * tree.c (build_common_builtin_nodes): Do not set ECF_NOTHROW on + __builtin_alloca if stack checking is enabled. + * unwind-dw2.c (uw_identify_context): Take into account whether the + context is that of a signal frame or not. + * config/i386/linux.h (STACK_CHECK_MOVING_SP): Define to 1. + * config/i386/linux64.h (STACK_CHECK_MOVING_SP): Likewise. + +2009-11-03 Jakub Jelinek + + PR rtl-optimization/41917 + * rtlanal.c (num_sign_bit_copies1) : If sign bit of second + operand isn't known to be 0, return 1. + +2009-11-03 Richard Sandiford + + * config/mips/mips.md: Fix typos. + +2009-11-03 Richard Sandiford + + * doc/invoke.texi: Fix typo. + +2009-11-03 Paul Brook + + * config/arm/neon.ml (vectype): Add T_floatSF. + (string_of_vectype): Ditto. + * config/arm/neon-gen.ml (signed_ctype): Add T_floatSF. + (deftypes): Use float for float32_t. + * config/arm/arm_neon.h: Regenerate. + +2009-11-03 Nick Clifton + Kevin Buettner + + * config/rx/predicates.md (rx_store_multiple_vector): Reverse + order of expected registers. + (rx_load_multiple_vector): Likewise. + (rx_rtsd_vector): Likewise. + * config/rx/rx.c (rx_cpu_type): New variable. + (rx_print_operand): Fix bug printing 64-bit constant values. + (rx_emit_stack_pushm): Reverse order of pushed registers. + (gen_rx_store_vector): Likewise. + (is_fast_interrupt_func): Only accept "fast_interrupt" as the + attribute name. + (is_exception_func): Rename to is_interrupt_func and only accept + "interrupt" as the attribute name. + (rx_get_stack_layout): Use new function name. + (rx_func_attr_inlinable): Likewise. + (rx_attribute_table): Remove "exception". + (rx_expand_prologue): If necessary push the accumulator register + in the prologue of interrupt functions. + (rx_expand_epilogue): If necessary pop the accumulator. + (rx_builtins): Add RX_BUILTIN_MVTIPL. + (rx_expand_builtin_stz): Remove. + (rx_expand_builtin_mvtipl): New function. + (rx_init_builtins): Handle RX_BUILTIN_MVTIPL. + (rx_expand_builtin): Likewise. + (rx_enable_fpu): New variable. + (rx_handle_option): Handle -fpu, -nofpu, -mcpu and -patch. + * config/rx/rx.h (TARGET_CPU_CPP_BUILTINS): Assert machine based + on rx_cpu_type. Define __RX_FPU_INSNS__ if FPU insns are allowed. + (enum rx_cpu_types): Define. + (ASM_SPEC): Pass -m32bit-doubles on to assembler. + (INCOMING_FRAME_SP_OFFSET): Define. + (ARG_POINTER_CFA_OFFSET): Define. + (FRAME_POINTER_CFA_OFFSET): Define. + (OVERRIDE_OPTIONS): Enable fast math if RX FPU insns are enabled. + (ALLOW_RX_FPU_INSNS): Define. + * config/rx/rx.md: Test ALLOW_RX_FPU_INSNS instead of + fast_math_flags_set_p. + (UNSPEC_BUILTIN_MVTIPL): Define. + (revl): Rename to bswapsi2. + (bswaphi2): New pattern. + (mvtachi): Mark as volatile because it uses a register unknown to GCC. + (mvtaclo): Likewise. + (racw): Likewise. + (mvtc): Remove clobber of cc0. + (mvtcp): Delete. + (opecp): Delete. + * config/rx/rx.opt (mieee): Remove. + (fpu): Add. + (nofpu): Add. + (mcpu=): Add. + (patch=): Add. + (msave-acc-in-interrupts): Add. + * config/rx/t-rx (MULTILIB_OPTIONS): Change default to 64bit doubles. + (MULTILIB_DIRS): Likewise. + (MULTILIB_MATCHES): Treat -fpu as an alias for -m32bit-doubles. + * doc/extend.texi: Remove description of "exception" function + attribute. + * doc/invoke.texi: Document -fpu, -nofpu, -mcpu=, -patch= and + -msave-acc-in-interrupts options. + +2009-11-03 Richard Guenther + + * c-common.c (fold_offsetof_1): Use HOST_WIDE_INT_PRINT_DEC. + +2009-11-03 Dodji Seketeli + + PR c++/38699 + * c-common.c (fold_offsetof_1): Issue errors when the member designator + of the offsetof expression is not legitimate. + +2009-11-03 Uros Bizjak + + * config/i386/i386.md (*call_value_1_rex64_ms_sysv): Use register + names instead of numerical constants. + (sse_prologue_save): Ditto. + (*sse_prologue_save_insn): Ditto. + +2009-11-03 Uros Bizjak + + PR target/41900 + * config/i386/i386.h (ix86_arch_indices) : New. + (TARGET_CALL_ESP): New define. + * config/i386/i386.c (initial_ix86_tune_features): Initialize + X86_ARCH_CALL_ESP. + * config/i386/i386.md (*call_pop_1_esp, *call_1_esp, + *call_value_pop_1_esp, *call_value_1_esp): Rename from *call_pop_1, + *call_1, *call_value_pop_1 and *call_value_1. Depend on + TARGET_CALL_ESP. + (*call_pop_1, *call_1, *call_value_pop_1, *call_value_1): + New patterns, use "lsm" as operand 1 constraint. + * config/i386/predicates.md (call_insn_operand): Depend on + index_register_operand for !TARGET_CALL_ESP to avoid %esp register. + +2009-11-02 Ulrich Weigand + + PR tree-optimization/41857 + * tree-flow.h (rewrite_use_address): Add BASE_HINT argument. + * tree-ssa-loop-ivopts.c (rewrite_use_address): Pass base hint + to create_mem_ref. + * tree-ssa-address.c (move_hint_to_base): New function. + (most_expensive_mult_to_index): Add TYPE argument. Use mode and + address space associated with TYPE. + (addr_to_parts): Add TYPE and BASE_HINT arguments. Pass TYPE to + most_expensive_mult_to_index. Call move_hint_to_base. + (create_mem_ref): Add BASE_HINT argument. Pass BASE_HINT and + TYPE to addr_to_parts. + +2009-11-02 Martin Jambor + + PR tree-optimization/41750 + * tree-sra.c (analyze_modified_params): Loop over all + representatives of components of a parameter. + +2009-11-02 Jakub Jelinek + + PR tree-optimization/41841 + * ipa-struct-reorg.c (build_data_structure): Don't attempt to look at + local variables of not yet materialized clones. + + PR debug/41893 + * cfgexpand.c (expand_debug_expr): Don't attempt to create DECL_RTL + for a VOIDmode variable. + + PR c++/41774 + * c-pragma.c (visstack): Change into vector of ints rather than + enum symbol_visibility. + (push_visibility): Add kind argument, push default_visibility together + with kind. + (pop_visibility): Add kind argument, return true if successful, fail + if visibility stack is empty or if stack top is of different kind. + (handle_pragma_visibility): Don't check length of visstack, instead + call pop_visibility and issue diagnostics if it failed. Pass 0 + as last argument to push_visibility and pop_visibility. + * c-pragma.h (push_visibility): Add kind argument. + (pop_visibility): Likewise. Return bool instead of void. + +2009-11-01 Eric Botcazou + + * tree.def (TARGET_MEM_REF): Update comment. + * alias.c (get_alias_set): Retrieve the original memory reference for + a TARGET_MEM_REF before proceeding. + +2009-10-31 Anatoly Sokolov + + * config/frv/frv.c (frv_function_value, frv_libcall_value, + frv_function_value_regno_p): New functions. + (TARGET_FUNCTION_VALUE, TARGET_LIBCALL_VALUE): Declare. + * config/frv/frv.h: (FUNCTION_VALUE, LIBCALL_VALUE): Remove. + (FUNCTION_VALUE_REGNO_P): Redefine, use frv_function_value_regno_p. + * config/frv/frv-protos.h (frv_function_value_regno_p): Declare. + +2009-10-31 Anatoly Sokolov + + * config/mn10300/mn10300.c (mn10300_function_value): Make static, add + new 'outgoing' argument. + (mn10300_libcall_value, mn10300_function_value_regno_p): New functions. + (TARGET_FUNCTION_VALUE, TARGET_LIBCALL_VALUE): Declare. + * config/mn10300/mn10300.h: (FUNCTION_VALUE, FUNCTION_OUTGOING_VALUE, + LIBCALL_VALUE): Remove. + (FUNCTION_VALUE_REGNO_P): Redefine, use mn10300_function_value_regno_p. + * config/mn10300/mn10300-protos.h (mn10300_function_value): Remove. + (mh10300_function_value_regno_p): Declare. + +2009-10-31 Ramana Radhakrishnan + + * config/arm/cortex-a9.md: New - integer pipeline description. + +2009-10-31 Eric Botcazou + + * tree-ssa-sccvn.c (vn_reference_lookup_3): Bail out instead of + aborting if the sizes of the two references don't match. + +2009-10-31 Toon Moene + + * ipa-inline.c (cgraph_decide_inlining): + Include reason for not inlining called-once functions in dump file. + +2009-10-30 Daniel Gutson + + * config/arm/linux-eabi.h (LINK_SPEC): BE8_LINK_SPEC added. + * config/arm/bpapi.h (BE8_LINK_SPEC): New define. + (LINK_SPEC): BE_LINK_SPEC added. + +2009-10-30 Richard Guenther + + PR lto/41858 + * lto-streamer.h (struct lto_file_decl_data): Remove fd member. + +2009-10-30 Nathan Sidwell + + * target-def.h (TARGET_ASM_TTYPE): Correct typo of TARGET_ARM_TTYPE. + * config/arm/unwind-arm.c (__gnu_Unwind_Backtrace): Remove unused + label. + +2009-10-30 Martin Jambor + + * tree-sra.c (build_ref_for_offset_1): Remove a comment. + +2009-10-30 H.J. Lu + + PR target/40838 + * cfgexpand.c (expand_stack_alignment): Call update_stack_boundary + first. Move assert on stack_alignment_estimated just before + setting stack_realign_needed. + (gimple_expand_cfg): Initialize stack_alignment_estimated to 0. + Don't call update_stack_boundary. + + * config/i386/i386.c (ix86_minimum_incoming_stack_boundary): New. + (verride_options): Don't check ix86_force_align_arg_pointer here. + (ix86_function_ok_for_sibcall): Use it. + (ix86_update_stack_boundary): Likewise. + + * config/i386/i386.h (STACK_REALIGN_DEFAULT): Update comments. + +2009-10-30 Richard Earnshaw + + * arm.md (QHSI): New mode iterator. + (movqi): If generating for thumb, then truncate any immediate to + 8 bits. + * thumb2.md (thumb2_movsi_shortim and peephole2 generator): Replace + with... + (thumb2_mov_shortim and peephole2 generator): ... iterator based + version. + +2009-10-29 Cary Coutant + + PR debug/41700 + * dwarf2out.c (dwarf2_debug_hooks): Add entries for new hook (two + locations in the source). + (store_vcall_insn): New function. + (lookup_vcall_insn): New function. + (dwarf2out_virtual_call_token): Use store_vcall_insn. + (dwarf2out_copy_call_info): New function. + (dwarf2out_virtual_call): Use lookup_vcall_insn. + * emit-rtl.c (try_split): Call copy_call_info debug hook. + * debug.h (struct gcc_debug_hooks): Add copy_call_info hook. + * debug.c (do_nothing_debug_hooks): Add dummy entry for new hook. + (debug_nothing_rtx_rtx): New dummy hook. + * dbxout.c (dbx_debug_hooks): Add dummy entry for new hook. + (xcoff_debug_hooks): Likewise. + * sdbout.c (sdb_debug_hooks): Likewise. + * vmsdbgout.c (vmsdbg_debug_hooks): Likewise. + +2009-10-29 David Daney + + * doc/invoke.texi (mmcount-ra-address): Document new command line + option. + * config/mips/mips.opt (mmcount-ra-address): New option. + * config/mips/mips-protos.h (mips_function_profiler): Declare new + function. + * config/mips/mips.c (struct mips_frame_info): Add ra_fp_offset + member. + (mips_for_each_saved_gpr_and_fpr): Set ra_fp_offset. + (mips_function_profiler): Moved from FUNCTION_PROFILER, and + rewritten. + * config/mips/mips.h (FUNCTION_PROFILER): Body of macro moved to + mips_function_profiler. + +2009-10-29 Steve Ellcey + + PR middle-end/37565 + PR target/38018 + * doc/tm.texi (OVERRIDE_OPTIONS): Update. + (TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE): New. + * optc-gen.awk (cl_target_option_restore): Include call to + targetm.override_options_after_change. + * target-def.h (TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE): New. + * target.h (override_options_after_change): New. + * c-common.c (parse_optimize_options): Call + targetm.override_options_after_change. + * config/ia64/ia64.c (TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE): New. + (ia64_override_options_after_change): New. + (ia64_override_options) Add call to above. + +2009-10-29 Michael Matz + + * tree-ssa-math-opts.c (execute_convert_to_rsqrt): Remove. + (gate_convert_to_rsqrt): Ditto. + (pass_convert_to_rsqrt): Ditto. + * tree-pass.h (pass_convert_to_rsqrt): Don't declare. + * passes.c (init_optimization_passes): Don't add pass_convert_to_rsqrt + to pass list. + + * config/i386/i386.c (ix86_emit_swdivsf): Change evaluation order. + +2009-10-29 Ramana Radhakrishnan + + * config/arm/arm.c (find_best_start): Fix type of remainder to be + unsigned. + +2009-10-29 Martin Jambor + + PR tree-optimization/41775 + * tree-sra.c (build_ref_for_offset): Unshare *expr if not NULL. + (generate_subtree_copies): Do not unshare agg. + (load_assign_lhs_subreplacements): Do not unshare rhs. + (sra_modify_assign): Do not unshare exprs. + (propagate_subacesses_accross_link): Renamed to + propagate_subaccesses_across_link. + +2009-10-29 Richard Earnshaw + + * arm.c (count_insns_for_constant): Rework to support counting for + thumb2 immediates as well. + (find_best_start): Split out from arm_gen_constant. + (arm_gen_constant): Rework to support XOR with immediate. + +2009-10-29 Chao-ying Fu + + * config/mips/mips.c (mips_emit_unary, mips_force_unary): New + functions. + (mips_expand_synci_loop): Use the length rtx to control the + synci loop from the begin rtx that points to the first byte of + the cache line. + +2009-10-28 Rafael Avila de Espindola + + * doc/invoke.texi: Rename -use-linker-plugin -fuse-linker-plugin. + +2009-10-28 Rafael Avila de Espindola + + * dbxout.c (dbxout_common_check): Accept non public trees. + * dwarf2out.c (fortran_common): Accept non public trees. + +2009-10-28 Rafael Avila de Espindola + + * common.opt (fuse-linker-plugin): New option. + * gcc.c (LINK_COMMAND_SPEC, main): Rename use-linker-plugin to + fuse-linker-plugin. + * opts.c (common_handle_option): Ignore OPT_fuse_linker_plugin. + +2009-10-28 Paolo Bonzini + + PR rtl-optimization/39715 + * config/arm/arm.md (cstoresi4): Use gen_cstoresi_ltu_thumb1. + (gen_cstoresi_ltu_thumb1): New splitter. + +2009-10-28 Richard Guenther + + PR lto/41808 + PR lto/41839 + * tree-ssa.c (useless_type_conversion_p): Do not treat + conversions to pointers to incomplete types as useless. + * gimple.c (gimple_types_compatible_p): Compare struct tags, + not typedef names. + +2009-10-28 Jakub Jelinek + + * var-tracking.c (emit_note_insn_var_location): Don't call the second + vt_expand_loc unnecessarily when location is not a register nor + memory. + + PR middle-end/41837 + * ipa-struct-reorg.c (find_field_in_struct_1): Return NULL if + fields don't have DECL_NAME. + + PR debug/41801 + * builtins.c (get_builtin_sync_mem): Expand loc in ptr_mode, + call convert_memory_address on addr. + + PR target/41762 + * config/i386/i386.c (ix86_pic_register_p): Don't call + rtx_equal_for_cselib_p for VALUEs discarded as useless. + +2009-10-28 Richard Sandiford + + * var-tracking.c (emit_note_insn_var_location): Get the mode of + a variable part from its REG, MEM or VALUE. + +2009-10-28 Richard Guenther + + * gimple.c (gimple_get_alias_set): Fix comment typo. + +2009-10-28 Richard Guenther + + * tree.c (free_lang_data_in_type): Do not call get_alias_set. + (free_lang_data): Unconditionally compute alias sets for all + standard integer types. Bail out if gate bailed out previously. + Do not reset the types_compatible_p langhook. + (gate_free_lang_data): Remove. + (struct pass_ipa_free_lang_data): Enable unconditionally. + * gimple.c (gimple_get_alias_set): Use the same alias-set for + all pointer types. + +2009-10-28 Richard Guenther + + PR middle-end/41855 + * tree-ssa-alias.c (refs_may_alias_p_1): Deal with CONST_DECLs + (ref_maybe_used_by_call_p_1): Fix bcopy handling. + (call_may_clobber_ref_p_1): Likewise. + * tree-ssa-structalias.c (find_func_aliases): Likewise. + * alias.c (nonoverlapping_memrefs_p): Deal with CONST_DECLs. + +2009-10-28 Paolo Bonzini + + PR rtl-optimization/41812 + + Revert: + 2009-06-27 Paolo Bonzini + + * df-problems.c (df_md_scratch): New. + (df_md_alloc, df_md_free): Allocate/free it. + (df_md_local_compute): Only include live registers in init. + (df_md_transfer_function): Prune the in-set computed by + the confluence function, and the gen-set too. + +2009-10-28 Paolo Bonzini + + PR rtl-optimization/39715 + * combine.c (simplify_comparison): Use extensions to + widen comparisons. Try an ANDing first. + +2009-10-28 Paolo Bonzini + + PR rtl-optimization/40741 + * config/arm/arm.c (thumb1_rtx_costs): IOR or XOR with + a small constant is cheap. + * config/arm/arm.md (andsi3, iorsi3): Try to place the result of + force_reg on the LHS. + (xorsi3): Likewise, and split the XOR if the constant is complex + and not in Thumb mode. + +2009-10-28 Paolo Bonzini + + * expmed.c (emit_store_flag): Check costs before + transforming to the opposite representation. + +2009-10-28 Paolo Bonzini + + * config/sh/sh.md (cbranchfp4_media): Remove hack extending + cstore result to DImode. + +2009-10-28 Kaz Kojima + + * config/sh/sh.md (stuff_delay_slot): Move const_int pattern + inside the unspec vector. + +2009-10-27 Richard Henderson + + * cgraphunit.c (cgraph_optimize): Maintain timevar stack properly. + +2009-10-27 Richard Henderson + + PR c++/41819 + * tree-eh.c (eh_region_may_contain_throw_map): Rename from + eh_region_may_contain_throw; update users. + (eh_region_may_contain_throw): New function. + (lower_catch): Check flag_exceptions before creating exception region. + (lower_eh_filter, lower_eh_must_not_throw): Likewise. + (lower_cleanup): Tidy existing flag_exceptions check to match. + +2009-10-27 Kai Tietz + + PR/41799 + * config/i386/mingw32.h (CHECK_EXECUTE_STACK_ENABLED): New macro. + * config/i386/mingw.opt: Add fset-stack-executable. + * config/i386/i386.c (ix86_trampoline_init): Make call to + emit_library_call conditional, if CHECK_EXECUTE_STACK_ENABLED is + defined and its value is not zero. + * doc/invoke.texi + +2009-10-27 Richard Guenther + + * tree-ssa-structalias.c (find_func_aliases): In IPA mode + handle calls to externally visible functions like in regular mode. + (create_variable_info_for): Do not create function infos here. + (have_alias_info): Remove write-only variable. + (solve_constraints): New function split out from common code + in compute_points_to_sets and ipa_pta_execute. + (compute_points_to_sets): Adjust. + (ipa_pta_execute): Likewise. Handle clones and externally visible + functions like in non-IPA mode. + +2009-10-27 Jakub Jelinek + + PR c/41842 + * c-typeck.c (convert_arguments): Return -1 if any of the arguments is + error_mark_node. + +2009-10-27 Richard Guenther + + * tree-complex.c (expand_complex_div_wide): Check for + INTEGER_CST, not TREE_CONSTANT on comparison folding result. + +2009-10-27 Revital Eres + + PR tree-optimization/40648 + * tree-vect-data-refs.c (vect_enhance_data_refs_alignment): + Change decision of when to peel for alignment. + +2009-10-27 Richard Guenther + + PR lto/41821 + * gimple.c (gimple_types_compatible_p): Handle OFFSET_TYPE. + +2009-10-27 Aldy Hernandez + + PR bootstrap/41451 + * fold-const.c (fold_binary_loc): Do not call + protected_set_expr_location. + +2009-10-27 Wei Guozhi + + PR target/41705 + * target.h (have_conditional_execution): Add a new target hook + function. + * target-def.h (TARGET_HAVE_CONDITIONAL_EXECUTION): Likewise. + * targhooks.h (default_have_conditional_execution): Likewise. + * targhooks.c (default_have_conditional_execution): Likewise. + * doc/tm.texi (TARGET_HAVE_CONDITIONAL_EXECUTION): Document it. + * config/arm/arm.c (TARGET_HAVE_CONDITIONAL_EXECUTION): Define it. + (arm_have_conditional_execution): New function. + * ifcvt.c (noce_process_if_block, find_if_header, + cond_exec_find_if_block, dead_or_predicable): Change the usage of + macro HAVE_conditional_execution to a target hook call. + * recog.c (peephole2_optimize): Likewise. + * sched-rgn.c (add_branch_dependences): Likewise. + * final.c (asm_insn_count, final_scan_insn): Likewise. + * bb-reorder.c (HAVE_conditional_execution): Remove it. + +2009-10-26 Ben Elliston + Michael Meissner + Ulrich Weigand + + * config.gcc (spu-*-elf*): Add spu_cache.h to extra_headers. + * config/spu/spu_cache.h: New file. + + * config/spu/cachemgr.c: New file. + * config/spu/cache.S: New file. + + * config/spu/spu.h (ASM_OUTPUT_SYMBOL_REF): Define. + (ADDR_SPACE_EA): Define. + (TARGET_ADDR_SPACE_KEYWORDS): Define. + * config/spu/spu.c (EAmode): New macro. + (TARGET_ADDR_SPACE_POINTER_MODE): Define. + (TARGET_ADDR_SPACE_ADDRESS_MODE): Likewise. + (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Likewise. + (TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Likewise. + (TARGET_ADDR_SPACE_SUBSET_P): Likewise. + (TARGET_ADDR_SPACE_CONVERT): Likewise. + (TARGET_ASM_SELECT_SECTION): Likewise. + (TARGET_ASM_UNIQUE_SECTION): Likewise. + (TARGET_ASM_UNALIGNED_SI_OP): Likewise. + (TARGET_ASM_ALIGNED_DI_OP): Likewise. + (ea_symbol_ref): New function. + (spu_legitimate_constant_p): Handle __ea qualified addresses. + (spu_addr_space_legitimate_address_p): New function. + (spu_addr_space_legitimize_address): Likewise. + (cache_fetch): New global. + (cache_fetch_dirty): Likewise. + (ea_alias_set): Likewise. + (ea_load_store): New function. + (ea_load_store_inline): Likewise. + (expand_ea_mem): Likewise. + (spu_expand_mov): Handle __ea qualified memory references. + (spu_addr_space_pointer_mode): New function. + (spu_addr_space_address_mode): Likewise. + (spu_addr_space_subset_p): Likewise. + (spu_addr_space_convert): Likewise. + (spu_section_type_flags): Handle "._ea" section. + (spu_select_section): New function. + (spu_unique_section): Likewise. + * config/spu/spu-c.c (spu_cpu_cpp_builtins): Support __EA32__ + and __EA64__ predefined macros. + * config/spu/spu-elf.h (LIB_SPEC): Handle -mcache-size= and + -matomic-updates switches. + + * config/spu/t-spu-elf (MULTILIB_OPTIONS): Define. + (EXTRA_MULTILIB_PARTS): Add libgcc_cachemgr.a, + libgcc_cachemgr_nonatomic.a, libgcc_cache8k.a, libgcc_cache16k.a, + libgcc_cache32k.a, libgcc_cache64k.a, libgcc_cache128k.a. + ($(T)cachemgr.o, $(T)cachemgr_nonatomic.o): New target. + ($(T)cache8k.o, $(T)cache16k.o, $(T)cache32k.o, $(T)cache64k.o, + $(T)cache128k.o): Likewise. + ($(T)libgcc_%.a): Likewise. + + * config/spu/spu.h (TARGET_DEFAULT): Add MASK_ADDRESS_SPACE_CONVERSION. + * config/spu/spu.opt (-mea32/-mea64): Add switches. + (-maddress-space-conversion): Likewise. + (-mcache-size=): Likewise. + (-matomic-updates): Likewise. + * doc/invoke.texi (-mea32/-mea64): Document. + (-maddress-space-conversion): Likewise. + (-mcache-size=): Likewise. + (-matomic-updates): Likewise. + +2009-10-26 Ben Elliston + Michael Meissner + Ulrich Weigand + + * doc/tm.texi (TARGET_ADDR_SPACE_KEYWORDS): Document. + + * c-common.c (c_common_reswords): If TARGET_ADDR_SPACE_KEYWORDS is + defined, add the named address space keywords. + (c_addr_space_name): New function. + (complete_array_type): Preserve named address space. + (handle_mode_attribute): Use targetm.addr_space.valid_pointer_mode + instead of targetm.valid_pointer_mode. + + * c-common.h (enum rid): Add RID_ADDR_SPACE_0 .. RID_ADDR_SPACE_15, + RID_FIRST_ADDR_SPACE and RID_LAST_ADDR_SPACE. + (ADDR_SPACE_KEYWORD): New macro. + (c_addr_space_name): Add prototype. + + * c-tree.h (struct c_declspecs): Add address_space member. + (declspecs_add_addrspace): Add prototype. + + * c-pretty-print.c (pp_c_type_qualifier_list): Handle address spaces. + + * c-parser.c (c_parse_init): Add assertion. + (typedef enum c_id_kind): Add C_ID_ADDRSPACE. + (c_lex_one_token): Handle address space keywords. + (c_token_starts_typename): Likewise. + (c_token_starts_declspecs): Likewise. + (c_parser_declspecs): Likewise. + (c_parser_postfix_expression_after_paren_type): Diagnose compound + literal within function qualified with named address space. + + * c-decl.c (diagnose_mismatched_decls): Diagnose conflicting named + address space qualifiers. + (shadow_tag_warned): Warn about useless address space qualifiers. + (quals_from_declspecs): Handle address space qualifiers. + (grokdeclarator): Likewise. + (build_null_declspecs): Likewise. + (declspecs_add_addrspace): New function. + + * c-typeck.c (addr_space_superset): New function. + (qualify_type): Handle named address spaces. + (composite_type): Likewise. + (common_pointer_type): Likewise. + (comp_target_types): Likewise. + (build_conditional_expr): Likewise. + (handle_warn_cast_qual): Likewise. + (build_c_cast): Likewise. + (convert_for_assignment): Likewise. + (build_binary_op): Likewise. + (pointer_diff): Handle named address spaces. Use intermediate + integer type of sufficient size if required. + +2009-10-26 Ben Elliston + Michael Meissner + Ulrich Weigand + + * doc/tm.texi (TARGET_ADDR_SPACE_POINTER_MODE): Document. + (TARGET_ADDR_SPACE_ADDRESS_MODE): Likewise. + (TARGET_ADDR_SPACE_VALID_POINTER_MODE): Likewise. + + * target.h (struct target_def): Add pointer_mode, address_mode, + and valid_pointer_mode to addr_space substructure. + * target-def.h (TARGET_ADDR_SPACE_POINTER_MODE): Define. + (TARGET_ADDR_SPACE_ADDRESS_MODE): Likewise. + (TARGET_ADDR_SPACE_VALID_POINTER_MODE): Likewise. + (TARGET_ADDR_SPACE_HOOKS): Add them. + * targhooks.c (target_default_pointer_address_modes_p): New function. + * target.h (target_default_pointer_address_modes_p): Add prototype. + * targhooks.c (default_addr_space_pointer_mode): New function. + (default_addr_space_address_mode): Likewise. + (default_addr_space_valid_pointer_mode): Likewise. + * targhooks.h (default_addr_space_pointer_mode): Add prototype. + (default_addr_space_address_mode): Likewise. + (default_addr_space_valid_pointer_mode): Likewise. + * output.h (default_valid_pointer_mode): Move to ... + * targhooks.h (default_valid_pointer_mode): ... here. + * varasm.c (default_valid_pointer_mode): Move to ... + * targhooks.c (default_valid_pointer_mode): ... here. + + * varasm.c (output_constant): Use targetm.addr_space.valid_pointer_mode + instead of targetm.valid_pointer_mode. + + * fold-const.c (fit_double_type): Use int_or_pointer_precision. + * tree.c (integer_pow2p): Likewise. + (tree_log2): Likewise. + (tree_floor_log2): Likewise. + (signed_or_unsigned_type_for): Support pointer type of different size. + (int_or_pointer_precision): New function. + * tree.h (int_or_pointer_precision): Add prototype. + * stor-layout.c (layout_type): Set TYPE_PRECISION for offset types. + * varasm.c (initializer_constant_valid_p): Use TYPE_PRECISION of + incoming pointer type instead of POINTER_SIZE. + + * tree.c (build_pointer_type): Use appropriate pointer mode + instead of ptr_mode. + (build_reference_type): Likewise. + * expr.c (store_expr): Likewise. + (expand_expr_addr_expr): Likewise. + * tree-vect-data-refs.c (vect_create_data_ref_ptr): Likewise. + * cfgexpand.c (expand_debug_expr): Likewise. + + * auto-inc-dec.c: Include "target.h". + (try_merge): Use appropriate address mode instead of Pmode. + (find_inc): Likewise. + * combine.c (find_split_point): Likewise. + * cselib.c (cselib_record_sets): Likewise. + * dse.c (replace_inc_dec): Likewise. + (canon_address): Likewise. + * var-tracking.c (replace_expr_with_values): Likewise. + (count_uses): Likewise. + (add_uses): Likewise. + (add_stores): Likewise. + * emit-rtl.c: Include "target.h". + (adjust_address_1): Use appropriate address mode instead of Pmode. + (offset_address): Likewise. + * explow.c (break_out_memory_refs): Likewise. + (memory_address_addr_space): Likewise. + (promote_mode): Likewise. + * expr.c (move_by_pieces): Likewise. + (emit_block_move_via_loop): Likewise. + (store_by_pieces): Likewise. + (store_by_pieces_1): Likewise. + (expand_assignment): Likewise. + (store_constructor): Likewise. + (expand_expr_addr_expr): Likewise. + (expand_expr_real_1): Likewise. + * cfgexpand.c (expand_debug_expr): Likewise. + * ifcvt.c (noce_try_cmove_arith): Likewise. + * regcprop.c (kill_autoinc_value): Likewise. + * regmove.c (try_auto_increment): Likewise. + * reload.c (find_reloads): Likewise. + (find_reloads_address): Likewise. + (find_reloads_address_1): Likewise. + * sched-deps.c: Include "target.h". + (sched_analyze_1): Use appropriate address mode instead of Pmode. + (sched_analyze_2): Likewise. + * sel-sched-dump.c: Include "target.h". + (debug_mem_addr_value): Use appropriate address mode instead of Pmode. + * stor-layout.c (layout_type): Likewise. + * tree-ssa-loop-ivopts.c (produce_memory_decl_rtl): Likewise. + (multiplier_allowed_in_address_p): Likewise. + (get_address_cost): Likewise. + * varasm.c (make_decl_rtl): Likewise. + + * expr.c (expand_assignment): Always convert offsets to appropriate + address mode. + (store_expr): Likewise. + (store_constructor): Likewise. + (expand_expr_real_1): Likewise. + + * reload.h (form_sum): Add MODE argument. + * reload.c (form_sum): Add MODE argument, use it instead of Pmode. + Update recursive calls. + (subst_indexed_address): Update calls to form_sum. + + * tree-flow.h (addr_for_mem_ref): Add ADDRSPACE argument. + * tree-ssa-address.c: Include "target.h". + (templates): Replace by ... + (mem_addr_template_list): ... this new vector. + (TEMPL_IDX): Handle address space numbers. + (gen_addr_rtx): Add address mode argument, use it instead of Pmode. + (addr_for_mem_ref): Add ADDRSPACE argument. Use per-address-space + instead of global cache. Update call to gen_addr_rtx. + (valid_mem_ref_p): Update call to addr_for_mem_ref. + * expr.c (expand_expr_real_1): Update call to addr_for_mem_ref. + + * rtl.h (convert_memory_address_addr_space): Add prototype. + (convert_memory_address): Define as macro. + * explow.c (convert_memory_address): Rename to ... + (convert_memory_address_addr_space): ... this. Add ADDRSPACE argument. + Use appropriate pointer and address modes instead of ptr_mode / Pmode. + Update recursive calls. + (memory_address_addr_space): Call convert_memory_address_addr_space. + * expmed.c (make_tree): Likewise. + * expr.c (expand_assignment): Likewise. + (expand_expr_addr_expr_1): Likewise. Also, add ADDRSPACE argument. + (expand_expr_addr_expr): Likewise. Also, update call. + + * alias.c (find_base_value): Guard pointer size optimizations. + (find_base_term): Likewise. + * rtlanal.c (nonzero_bits1): Likewise. + (num_sign_bit_copies1): Likewise. + * simplify-rtx.c (simplify_unary_operation_1): Likewise. + + * Makefile.in (tree-ssa-address.o): Add $(TARGET_H) dependency. + (emit-rtl.o): Likewise. + (auto-inc-dec.o): Likewise. + (sched-deps.o): Likewise. + +2009-10-26 Ben Elliston + Michael Meissner + Ulrich Weigand + + * doc/extend.texi (Named Address Spaces): New section. + * coretypes.h (addr_space_t): New type. + (ADDR_SPACE_GENERIC): New define. + (ADDR_SPACE_GENERIC_P): New macro. + + * doc/tm.texi (Named Address Spaces): New section. + (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Document. + (TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Document. + (TARGET_ADDR_SPACE_SUBSET_P): Document. + (TARGET_ADDR_SPACE_CONVERT): Document. + * target.h (struct gcc_target): Add addr_space substructure. + * target-def.h (TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P): Define. + (TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS): Likewise. + (TARGET_ADDR_SPACE_SUBSET_P): Likewise. + (TARGET_ADDR_SPACE_CONVERT): Likewise. + (TARGET_ADDR_SPACE_HOOKS): Likewise. + (TARGET_INITIALIZER): Initialize addr_space hooks. + * targhooks.c (default_addr_space_legitimate_address_p): New function. + (default_addr_space_legitimize_address): Likewise. + (default_addr_space_subset_p): Likewise. + (default_addr_space_convert): Likewise. + * targhooks.h (default_addr_space_legitimate_address_p): Add prototype. + (default_addr_space_legitimize_address): Likewise. + (default_addr_space_subset_p): Likewise. + (default_addr_space_convert): Likewise. + + * doc/rtl.texi (MEM_ADDR_SPACE): Document. + * rtl.h (mem_attrs): Add ADDRSPACE memory attribute. + (MEM_ADDR_SPACE): New macro. + * emit-rtl.c (get_mem_attrs): Add ADDRSPACE argument and set + address space memory attribute. + (mem_attrs_htab_hash): Handle address space memory attribute. + (mem_attrs_htab_eq): Likewise. + (set_mem_attributes_minus_bitpos): Likewise. + (set_mem_alias_set): Likewise. + (set_mem_align): Likewise. + (set_mem_expr): Likewise. + (set_mem_offset): Likewise. + (set_mem_size): Likewise. + (adjust_address_1): Likewise. + (offset_address): Likewise. + (widen_memoy_address): Likewise. + (get_spill_slot_decl): Likewise. + (set_mem_attrs_for_spill): Likewise. + (set_mem_addr_space): New function. + * emit-rtl.h (set_mem_addr_space): Add prototype. + * print-rtl.c (print_rtx): Print address space memory attribute. + * expr.c (expand_assignment): Set address space memory attribute + of generated MEM RTXes as appropriate. + (expand_expr_real_1): Likewise. + * cfgexpand.c (expand_debug_expr): Likewise. + * tree-ssa-loop-ivopts.c (produce_memory_decl_rtl): Likewise. + + * tree.h (struct tree_base): Add address_space bitfield. Reduce + size of "spare" bitfield. + (TYPE_ADDR_SPACE): New macro. + (ENCODE_QUAL_ADDR_SPACE): Likewise. + (DECODE_QUAL_ADDR_SPACE): Likewise. + (CLEAR_QUAL_ADDR_SPACE): Likewise. + (KEEP_QUAL_ADDR_SPACE): Likewise. + (TYPE_QUALS): Encode type address space. + (TYPE_QUALS_NO_ADDR_SPACE): New macro. + * tree.c (set_type_quals): Set type address space. + (build_array_type): Inherit array address space from element type. + * print-tree.c (print_node_brief): Print type address space. + (print_node): Likewise. + * tree-pretty-print.c (dump_generic_node): Likewise. + + * explow.c (memory_address): Rename to ... + (memory_address_addr_space): ... this. Add ADDRSPACE argument. + Use address-space aware variants of memory address routines. + * recog.c (memory_address_p): Rename to ... + (memory_address_addr_space_p): ... this. Add ADDSPACE argument. + Use address-space aware variants of memory address routines. + (offsettable_address_p): Rename to ... + (offsettable_address_addr_space_p): ... this. Add ADDRSPACE argument. + Use address-space aware variants of memory address routines. + * reload.c (strict_memory_address_p): Rename to ... + (strict_memory_address_addr_space_p): ... this. Add ADDSPACE argument. + Use address-space aware variants of memory address routines. + (maybe_memory_address_p): Rename to ... + (maybe_memory_address_addr_space_p): ... this. Add ADDSPACE argument. + Use address-space aware variants of memory address routines. + * expr.h (memory_address_addr_space): Add prototype. + (memory_address): Define as macro. + * recog.h (memory_address_addr_space_p): Add prototype. + (memory_address_p): Define as macro. + (offsettable_address_addr_space_p): Add prototype. + (offsettable_address_p): Define as macro. + (strict_memory_address_addr_space_p): Add prototype. + (strict_memory_address_p): Define as macro. + + * combine.c (find_split_point): Use address-space aware variants + of memory address routines. + * emit-rtl.c (operand_subword): Likewise. + (change_address_1): Likewise. + (adjust_address_1): Likewise. + (offset_address): Likewise. + * expr.c (emit_move_insn): Likewise. + (expand_assignment): Likewise. + (expand_expr_real_1): Likewise. + * recog.c (verify_changes): Likewise. + (general_operand): Likewise. + (offsettable_memref_p): Likewise. + (offsettable_nonstrict_memref_p): Likewise. + (constrain_operands): Likewise. + * reload.c (get_secondary_mem): Likewise. + (find_reloads_toplev): Likewise. + (find_reloads_address): Likewise. + (find_reloads_subreg_address): Likewise. + * reload1.c (reload): Likewise. + * rtlhooks.c (gen_lowpart_if_possible): Likewise. + * rtl.h (address_cost): Add ADDRSPACE argument. + * rtlanal.c (address_cost): Add ADDRSPACE argument. Use address-space + aware variant of memory address routines. + * loop-invariant.c (create_new_invariant): Update address_cost call. + * tree-ssa-loop-ivopts.c (computation_cost): Likewise. + * fwprop.c (should_replace_address): Add ADDRSPACE argument. + Use address-space aware variant of memory address routines. + (propagate_rtx_1): Update call to should_replace_address. + * tree-flow.h (multiplier_allowed_in_address_p): Add ADDRSPACE + argument. + * tree-ssa-loop-ivopts.c (multiplier_allowed_in_address_p): Add + ADDRSPACE argument. Use per-address-space instead of global cache. + Use address-space aware variant of memory address routines. + (get_address_cost): Likewise. + (get_computation_cost_at): Update calls. + * tree-ssa-address.c (valid_mem_ref_p): Add ADDRSPACE argument. + Use address-space aware variant of memory address routines. + (create_mem_ref_raw): Update call to valid_mem_ref_p. + (most_expensive_mult_to_index): Update call to + multiplier_allowed_in_address_p. + + * dwarf2out.c (modified_type_die): Output DW_AT_address_class + attribute to indicate named address spaces. + + * varasm.c (get_variable_section): DECLs in named address spaces + cannot be "common". + + * reload.c (find_reloads_address): Do not use LEGITIMIZE_RELOAD_ADDRESS + for addresses in a non-generic address space. + + * expr.c (emit_block_move_hints): Do not use libcalls for + memory in non-generic address spaces. + (clear_storage_hints): Likewise. + (expand_assignment): Likewise. + + * fold-const.c (operand_equal_p): Expressions refering to different + address spaces are not equivalent. + + * rtl.c (rtx_equal_p_cb): MEMs refering to different address + spaces are not equivalent. + (rtx_equal_p): Likewise. + * cse.c (exp_equiv_p): Likewise. + * jump.c (rtx_renumbered_equal_p): Likewise. + * reload.c (operands_match_p): Likewise. + + * alias.c (nonoverlapping_memrefs_p): MEMs refering to different + address spaces may alias. + (true_dependence): Likewise. + (canon_true_dependence): Likewise. + (write_dependence_p): Likewise. + + * dse.c (canon_address): Handle named address spaces. + * ifcvt.c (noce_try_cmove_arith): Likewise. + + * tree.def (ADDR_SPACE_CONVERT_EXPR): New tree code. + * expr.c (expand_expr_real_2): Expand ADDR_SPACE_CONVERT_EXPR. + * convert.c (convert_to_pointer): Generate ADDR_SPACE_CONVERT_EXPR + to handle conversions between different address spaces. + * fold-const.c (fold_convert_loc): Likewise. + (fold_unary_loc): Handle ADDR_SPACE_CONVERT_EXPR. + * tree-pretty-print.c (dump_generic_node): Likewise. + * gimple-pretty-print.c (dump_unary_rhs): Likewise. + * tree-cfg.c (verify_gimple_assign_unary): Likewise. + * tree-inline.c (estimate_operator_cost): Likewise. + * tree-ssa.c (useless_type_conversion_p): Conversions between pointers + to different address spaces are not useless. + +2009-10-26 Jakub Jelinek + + PR bootstrap/41345 + * cfgcleanup.c (trivially_empty_bb_p): New function. + (try_optimize_bb): Use it instead of checking BB_HEAD == BB_END. + + PR debug/41828 + * dwarf2out.c (add_pubname, add_pubtype, generic_parameter_die, + add_name_and_src_coords_attributes, gen_namespace_die, + dwarf2out_set_name): Handle dwarf2_name returning NULL. + +2009-10-26 Nick Clifton + + * config.gcc: Add support for RX target. + * config/rx: New directory. + * config/rx/constraints.md: New file. + * config/rx/predicates.md: New file. + * config/rx/rx.c: New file. + * config/rx/rx.h: New file. + * config/rx/rx.md: New file. + * config/rx/rx.opt: New file. + * config/rx/rx-protos.h: New file. + * config/rx/t-rx: New file. + * doc/extend.texi: Document RX function attributes. + * doc/invoke.texi: Document RX specific command line options. + * doc/contrib.texi: Document RX contribution. + * doc/md.texi: Document RX constraints. + * doc/install.texi: Document RX support. + +2009-10-26 Michael Matz + + PR tree-optimization/41783 + * tree-ssa-alias.c (get_continuation_for_phi): Export, add a special + case for simple diamonds. + * tree-ssa-alias.h (get_continuation_for_phi): Declare. + * tree-ssa-pre.c (translate_vuse_through_block): Add same_valid + argument, use alias oracle to skip some vdefs. + (phi_translate_1): Change call to above, don't allocate new + value ids if they can stay the same. + (compute_avail): Allow vuse walking when looking up references. + +2009-10-26 Richard Guenther + + PR tree-optimization/41826 + * tree-ssa-structalias.c (get_constraint_for_ptr_offset): Avoid + access to re-allocated vector fields. + +2009-10-26 Richard Guenther + + * graphite-sese-to-poly.c (check_poly_representation): Fix + compile without checking. + +2009-10-26 Janus Weil + + PR fortran/41714 + * gimple.h (tree_annotate_all_with_location): Remove prototype. + * gimplify.c (tree_should_carry_location_p, + tree_annotate_one_with_location,tree_annotate_all_with_location): + Remove obsolete functions. + +2009-10-25 Kaz Kojima + + PR target/41813 + * config/sh/sh.md (stuff_delay_slot): Don't set T_REG in pattern. + +2009-10-25 Richard Guenther + + * lto-streamer-in.c (unpack_ts_decl_common_value_fields): + Stream DECL_RESTRICTED_P. + * lto-streamer-out.c (pack_ts_decl_common_value_fields): Likewise. + +2009-10-25 Richard Sandiford + + * config/mips/mips.c (mips_restore_gp_from_cprestore_slot): Emit + a note when expanding to nothing. + +2009-10-25 Richard Guenther + + PR middle-end/41814 + * tree.c (find_decls_types_r): Deal with Java overloading + BINFO_VIRTUALS for its own purpose. + +2009-10-24 Adam Nemet + + * config/mips/predicates.md (hilo_operand): New predicate. + * config/mips/mips.md (mulsidi3_64bit): Change it to a + define_insn. Correct !ISA_HAS_EXT_INS length from 24 to 28. Move + splitter part from here ...: + (mulsidi3_64bit splitter for !ISA_HAS_EXT_INS): ... to here. Swap + op0 and op4 to match the DINS case. + (mulsidi3_64bit splitter for ISA_HAS_EXT_INS): New splitter. + +2009-10-24 Andy Hutchinson + + PR middle-end/19154 + * avr.md (QIDI): Add new mode iterator. + (sbrx_branch): Create new zero extract bit, test and jump + patterns for all QI thru DI modes combinations. + (sbrx_and_branch): Create new and based bit test and jump + patterns for QI thru SI modes. + avr.c (avr_out_sbxx_branch): Use only bit number. + +2009-10-24 Jan Hubicka + + * ipa-reference.c (check_call): Noreturn notrhow calls do not write + to memory. + (analyze_function): When analyzing noreturn nothrow call, do not + compute written stats; free bitmaps of vars early if possible. + (generate_summary): Only update bitmaps if computed. + (propagate): Only dump bitmaps if computed. + (ipa_reference_read_summary): Fix pasto. + +2009-10-24 Eric Botcazou + + * tree-ssa-alias.c (nonaliasing_component_refs_p): Rename into... + (aliasing_component_refs_p): ...this. Return true if there is no + common base and the base access types have the same alias set. + (indirect_ref_may_alias_decl_p): Adjust for above renaming. + (indirect_refs_may_alias_p): Likewise. + +2009-10-23 Joseph Myers + + PR c/40033 + * c-typeck.c (c_finish_stmt_expr): Do not wrap error_mark_node in + a C_MAYBE_CONST_EXPR. + +2009-10-23 Michael Meissner + + PR target/41787 + * config/rs6000/rs6000.c (struct machine_function): Add + vsx_or_altivec_used_p to record if vector types are used. + (rs6000_expand_to_rtl_hook): Rename from + rs6000_alloc_sdmode_stack_slot. If VSX, check to see if there are + any vector operations, so if there are, we can set VRSAVE to + non-zero when only floating point vector registers are used. + (TARGET_EXPAND_TO_RTL_HOOK): Use rs6000_expand_to_rtl_hook. + (rs6000_check_vector_mode): Inner function to check if vector + types are used in the code. + (compute_vrsave_mask): If VSX, make sure VRSAVE is non-zero if + vector instructions are used. + + * config/rs6000/rs6000.h (HARD_REGNO_CALL_PART_CLOBBERED): + Indicate that VSX registers which overlap floating point + registers, can't be used across a call, since the ABI only states + the scalar part of the register will be saved and restored. + +2009-10-23 Joseph Myers + + PR c/41673 + * alias.c (get_alias_set): Call langhook before returning 0 for + types with structural equality. + * c-common.c (c_common_get_alias_set): Use alias set of element + type for arrays with structural comparison. + +2009-10-23 Richard Guenther + + PR middle-end/41805 + * cfgexpand.c (expand_call_stmt): Use gimple_has_side_effects and + gimple_call_nothrow_p. + +2009-10-23 Richard Guenther + + PR tree-optimization/41778 + * tree-ssa-pre.c (do_regular_insertion): Only insert if a + redundancy along a path in the CFG we want to optimize for speed + is going to be removed. + (execute_pre): Do partial-PRE only if the function is to be + optimized for speed. + (gate_pre): Do not turn off all of PRE when not optimizing a + function for speed. + +2009-10-23 Kaveh R. Ghazi + + * builtins.c (fold_builtin_cabs): Use validate_arg(). + (fold_builtin_cexp): Fix if-logic. + (fold_builtin_1): Check subtype for BUILT_IN_CIMAG. + +2009-10-22 Jeff Law + + * ira-lives.c (process_single_reg_class_operands): Update the + hard reg costs for all the hard registers desired by the + single reg class operand. + +2009-10-22 Richard Sandiford + + * simplify-rtx.c (simplify_replace_fn_rtx): Add a fallback case + for rtxes that aren't handled specially. + +2009-10-22 Richard Sandiford + + * rtl.h (shallow_copy_rtvec): Declare. + * rtl.c (shallow_copy_rtvec): New function. + * cselib.c (cselib_subst_to_values): Use it. Only modify an + rtx field if the subrtx has changed. + +2009-10-22 Anatoly Sokolov + + * config/m32c/m32c.c (m32c_function_value_regno_p): New function. + (m32c_function_value): Make static, add new 'outgoing' argument. + (m32c_libcall_value): Make static, add new 'fun' argument. + (TARGET_FUNCTION_VALUE, TARGET_LIBCALL_VALUE): Declare. + * config/m32c/m32c.h (FUNCTION_VALUE, LIBCALL_VALUE): Remove. + (FUNCTION_VALUE_REGNO_P): Redefine, use m32c_function_value_regno_p. + * config/m32c/m32c-protos.h (m32c_function_value_regno_p): Declare. + (m32c_function_value, m32c_libcall_value): Delete declaration. + +2009-10-22 Diego Novillo + + * Makefile.in (PLUGIN_HEADERS): Add output.h and IPA_UTILS_H. + +2009-10-22 Razya Ladelsky + + * tree-cfg.c (gimple_duplicate_sese_tail): Fix typos/indentation/white + space. + +2009-10-22 Richard Guenther + + * lto-streamer.h (lto_symtab_merge_cgraph_nodes): Declare. + * lto-symtab.c (struct lto_symtab_entry_def): Add node member. + (lto_symtab_merge): Do not merge cgraph nodes here. + (lto_symtab_resolve_can_prevail_p): Simplify. + (lto_symtab_resolve_symbols): Store cgraph node. + (lto_symtab_merge_decls_1): Simplify. Do not drop non-prevailing + functions from the symtab. + (lto_symtab_merge_cgraph_nodes_1): New function. + (lto_symtab_merge_cgraph_nodes): Likewise. + +2009-10-22 Richard Guenther + + PR lto/41791 + * lto-streamer-out.c (lto_output_location): Stream the + system header flag. + * lto-streamer-in.c (lto_input_location): Likewise. + +2009-10-22 Razya Ladelsky + + * cfgloopmanip.c (duplicate_subloops): Export. + * tree-parloops.c (loop_parallel_p): Dump if loop is innermost. + (transform_to_exit_first_loop): Duplicate bbs starting from + header up to loop->latch instead of exit->src. + Initialize control variable to the correct number of iterations. + (gather_scalar_reductions): Do not register double reductions. + (parallelize_loops): Dump which loop is tested. + Indicate whether the parallelized loop is inner or not. + Remove the innermost-loop requirement. + * cfgloop.h (duplicate_subloops): Export. + * tree-cfg.c (add_phi_args_after_redirect): New function. + (gimple_duplicate_sese_tail): Remove the no-subloops constraint. + Call duplicate_subloops. + Update number of iterations at the exit condition. + Don't redirect nexits always to the loop exit. + Redirect copied edges from latch to the loop exit. + +2009-10-22 Jan Hubicka + + * ipa-cp.c (ipcp_read_summary): Remove now invalid FIXME and + flag_ltrans check. + * ipa-inline.c (cgraph_mark_inline_edge, + cgraph_decide_inlining_of_small_function, + cgraph_decide_inlining, inline_read_summary): Disable indirect + inlining for WPA for time being. + + PR tree-optimize/40556 + * ipa-inline.c (cgraph_early_inlining): Fix iterations condition. + +2009-10-22 Richard Guenther + + * lto-streamer.h (lto_symtab_clear_resolution): Remove. + * lto-symtab.c (lto_symtab_clear_resolution): Likewise. + +2009-10-22 Jan Hubicka + + PR lto/41730 + * ipa-reference.c (has_proper_scope_for_analysis): Add fixme about + global vars. + (check_call): Handle only indirect calls. + (propagate_bits): Update comment. + (write_node_summary_p): Turn bogus check to assert. + (ipa_reference_write_summary): Stream calls_read_all properly. + (ipa_reference_read_summary): Stream in calls_read_all properly. + (read_write_all_from_decl): New function. + (propagate): Handle OVERWRITABLE nodes and external calls here. + * ipa-pre-const.c (check_call): In IPA mode handle indirect + calls only. + (analyze_function): Do not check visibility here. + (add_new_function): We summary OVERWRITABLE too. + (generate_summary): Stream OVERWRITABLE nodes too. + (propagate): Handle external calls and OVERWRITABLE nodes here. + (local_pure_const): Check visibility here. + +2009-10-22 Jan Hubicka + + * ipa-cp.c (ipcp_write_summary, ipcp_read_summary): New functions. + (pass_ipa_cp): Register them. + (ipcp_init_stage): Analyze all functions for whopr/lto. + (ipcp_propagate_stage): Skip external calls. + (ipcp_iterate_stage): Call ipa_update_after_lto_read if needed. + * ipa-reference.c (write_node_summary_p): Fix thinko about + availability. + * cgraphunit.c (ipa_passes): When in lto, ne er produce new summaries; + when in ltrans, skip executing of ipa passes since everything + should've been done. + * ipa-inline.c (cgraph_decide_inlining): Remove FIXMEs. + (inline_generate_summary): Likewise. + (inline_read_summary): New function. + (inline_write_summary): New function. + (pass_ipa_inline): Register new hooks. + * ipa-prop.c: Inlcude lto-streamer.h + (ipa_edge_args_vector): Update declaration. + (ipa_count_arguments, ipa_compute_jump_functions, + ipa_free_edge_args_substructures): Move ipa_edge_args_vector into ggc. + (ipa_write_jump_function, ipa_read_jump_function, ipa_write_node_info, + ipa_read_node_info): New static functions. + (ipa_prop_write_jump_functions, ipa_prop_read_jump_functions): Update. + (duplicate_array): Use xmalloc. + (duplicate_ggc_array): New. + (ipa_edge_duplication_hook): Use it. + (ipa_update_after_lto_read): New function. + * ipa-prop.h (ipa_prop_write_jump_functions, + ipa_prop_read_jump_functions): Declare. + (ipa_pass_through_data, ipa_ancestor_jf_data, ipa_member_ptr_cst, + jump_func_value, ipa_member_ptr_cst, ipa_edge_args): Add GTY markers. + (ipa_edge_args_vector): Move into GGC. + (ipa_check_create_edge_args): Update. + (ipa_update_after_lto_read): New. + * passes.c (ipa_write_summaries_1): When in wpa, do not write + summaries. + (ipa_read_summaries): When in ltrans, so not read summaries. + * lto-streamer.c (lto_get_section_name): Add + LTO_section_jump_functions. + * lto-streamer.h (LTO_section_jump_functions): New section. + (produce_asm): Declare. + * lto-cgraph.c (output_cgraph): Output edges in reverse order. + * lto-streamer-out.c (produce_asm): Export. + * lto-streamer-in.c: Include tree-pass.h + (input_function): Free dominance info when done. + (lto_read_body): Push ipa_inline in ltrans stage. + * gengtype.c (open_base_files): Add ipa-prop.h into includes. + * Makefile.in (GTFILES): Add ipa-prop.h + +2009-10-22 Matthias Klose + + * doc/install.texi: Document --enable-browser-plugin. + +2009-10-21 Vladimir Makarov + + * doc/invoke.texi (fira-loop-pressure): Update default value. + * opts.c (decode_options): Remove default value setting for + flag_ira_loop_pressure. + * config/ia64/ia64.c (ia64_override_options): Set + flag_ira_loop_pressure up for -O3. + * config/rs6000/rs6000.c (rs6000_override_options): Ditto. + +2009-10-21 Sebastian Pop + + PR tree-optimization/41497 + * tree-scalar-evolution.c (analyze_evolution_in_loop): Return + chrec_dont_know if the evolution function returned by follow_ssa_edge + is constant in the analyzed loop and is not compatible with the + initial value before the loop. + * tree-chrec.h (no_evolution_in_loop_p): Call STRIP_NOPS. + +2009-10-21 Joseph Myers + + * config/sh/sh.c (nonpic_symbol_mentioned_p): Allow UNSPEC_TPOFF. + +2009-10-21 Jakub Jelinek + + PR other/25507 + * doc/invoke.texi: Document -print-multi-os-directory. + +2009-10-21 Jack Howarth + + PR c++/41313 + * gcc/config/darwin10.h: Use default_emit_unwind_label. + * gcc/config/darwin.c: Disable -freorder-blocks-and-partition + when darwin_emit_unwind_label is used. + +2009-10-21 Eric Botcazou + + * tree-vect-stmts.c (exist_non_indexing_operands_for_use_p): Tweak + order of checks. + +2009-10-20 Richard Henderson + + * tree-eh.c (lower_try_finally_copy): Do lower_eh_constructs_1 + before emit_post_landing_pad. + +2009-10-20 Adam Nemet + + * config/mips/mips.c (mips_binary_cost): Add new argument speed. + Use when calling rtx_costs. + (mips_rtx_costs): Fix formatting. Use argument speed rather than the + global optimize_size. Pass speed to mips_binary_cost. + +2009-10-20 Jakub Jelinek + + * config/rs6000/rs6000.c (def_builtin): Set TREE_READONLY instead + of TREE_CONSTANT. + +2009-10-20 Richard Sandiford + + * rtl.h (simplify_replace_fn_rtx): Declare. + (wrap_constant, unwrap_constant): Delete. + * cfgexpand.c (unwrap_constant, wrap_constant): Delete. + (expand_debug_expr): Don't call wrap_constant. + * combine.c (rtx_subst_pair): Only define for AUTO_INC_DEC. + (auto_adjust_pair): Fold into... + (propagate_for_debug_subst): ...here. Only define for AUTO_INC_DEC. + Just return a new value. + (propagate_for_debug): Use simplify_replace_fn_rtx for AUTO_INC_DEC, + otherwise use simplify_replace_rtx. + * cselib.c (wrap_constant): Reinstate old definition. + (cselib_expand_value_rtx_1): Don't wrap constants. + * gcse.c (try_replace_reg): Don't use copy_rtx in the call to + simplify_replace_rtx. + (bypass_block): Fix formatting in calls to simplify_replace_rtx. + * reload1.c (reload): Skip all uses for an insn before adjusting it. + Use simplify_replace_rtx. + * simplify-rtx.c (simplify_replace_fn_rtx): New function, + adapted from... + (simplify_replace_rtx): ...here. Turn into a wrapper for + simplify_replace_fn_rtx. + (simplify_unary_operation): Don't unwrap CONSTs. + * var-tracking.c (check_wrap_constant): Delete. + (vt_expand_loc_callback): Don't call it. + (vt_expand_loc): Likewise. + +2009-10-20 Pascal Obry + Eric Botcazou + + * config/i386/cygming.h (DWARF_FRAME_REGNUM): Add enclosing parens. + +2009-10-20 Michael Matz + + * loop-invariant.c (create_new_invariant): Use different magic number. + +2009-10-20 Richard Earnshaw + + PR target/39247 + * arm.c (arm_override_options): Forcibly disable hot/cold block + partitioning. + +2009-10-20 Alexandre Oliva + + PR debug/41739 + * haifa-sched.c (try_ready): Skip debug deps updating speculation + status. + +2009-10-20 Richard Guenther + + * ggc-page.c: Include cfgloop.h. + (struct max_alignment): Drop long double, add void *. + (extra_order_size_table): Add low non-power-of-two multiples + of MAX_ALIGNMENT. Drop small type-based entries, add + tree_type, cgraph_node and loop. + * alloc-pool.c (struct allocation_object_def): Drop long double + aligning element. + +2009-10-20 Jakub Jelinek + + PR debug/41340 + * loop-invariant.c (calculate_loop_reg_pressure): Don't count regs + referenced just in DEBUG_INSNs. + +2009-10-20 Richard Guenther + + PR lto/41761 + * gimple.c (gimple_register_type): Make sure we register + the types main variant first. + +2009-10-20 Richard Guenther + + * gimple.c (gimple_types_compatible_p): Simplify. Move + cheap checks before hashtable queries. Add checks for + TYPE_NONALIASED_COMPONENT and DECL_NONADDRESSABLE_P. + +2009-10-20 Eric Botcazou + + * tree-sra.c (build_ref_for_offset_1) : Skip fields + without size or with size that can't be represented as a host integer. + +2009-10-20 Alexandre Oliva + + * tree-ssa-dce.c (eliminate_unnecessary_stmts): Don't regard + the removal of a debug stmt as a significant change. + +2009-10-20 Wolfgang Gellerich + + * config/s390/s390.md: Added agen condition to operand + forwarding bypasses. Added bypass for early address generation + use of int results. Updated comments. + +2009-10-20 Stefan Dösinger + + * config/i386/i386.c: Remove signal.h #include. + +2009-10-20 Jie Zhang + + * simplify-rtx.c (simplify_const_unary_operation): Handle SS_ABS. + * doc/rtl.texi: Document ss_abs. + +2009-10-19 Jakub Jelinek + + * c-common.c (c_parse_error): Handle CPP_UTF8STRING. + * c-lex.c (c_lex_with_flags): Likewise. Test C_LEX_STRING_NO_JOIN + instead of C_LEX_RAW_STRINGS. + (lex_string): Handle CPP_UTF8STRING. + * c-parser.c (c_parser_postfix_expression): Likewise. + * c-pragma.h (C_LEX_RAW_STRINGS): Rename to ... + (C_LEX_STRING_NO_JOIN): ... this. + +2009-10-19 Anatoly Sokolov + + * config/cris/cris.c (cris_function_value, cris_libcall_value, + cris_function_value_regno_p): New functions. + (cris_promote_function_mode): Update comment. + (TARGET_FUNCTION_VALUE, TARGET_LIBCALL_VALUE): Declare. + * config/cris/cris.h (FUNCTION_VALUE, LIBCALL_VALUE): Remove. + (FUNCTION_VALUE_REGNO_P): Redefine, use cris_function_value_regno_p. + * config/cris/cris-protos.h (cris_function_value_regno_p): Declare. + +2009-10-19 Jakub Jelinek + + * unwind-dw2.c (execute_stack_op): Fix operand order for + DW_OP_le, DW_OP_ge, DW_OP_lt and DW_OP_gt. + +2009-10-19 Eric Botcazou + + * gimple-low.c (struct lower_data): Add cannot_fallthru field. + (lower_stmt) : Add comment. + : Set cannot_fallthru to true + and return. + : Remove the statement if cannot_fallthru is set. + Otherwise lower it and set cannot_fallthru to true. + : Update cannot_fallthru for GIMPLE_TRY_FINALLY and return. + : Set cannot_fallthru to false. + : Set cannot_fallthru to false for BUILT_IN_SETJMP and + to true for a noreturn call. Do not remove statements. + : Set cannot_fallthru to false. + Set cannot_fallthru to false on function exit. + (gimple_stmt_may_fallthru) : Really return false. + : Remove. + +2009-10-19 Andreas Krebbel + + * config/s390/s390.c (s390_z10_optimize_cmp): Don't touch FP compares. + +2009-10-19 Andreas Krebbel + + * config/s390/s390.c (s390_z10_optimize_cmp): Use + next/prev_active_insn to skip DEBUG_INSNs as well. + +2009-10-19 Joseph Myers + + * config/arm/arm.c (output_move_neon): Use DImode in call to + adjust_address. + +2009-10-19 Matthias Klose + + PR target/40134 + * config.gcc (arm*-*-linux-*eabi): Use config/t-slibgcc-libgcc. + +2009-10-19 Jakub Jelinek + + * cfgexpand.c (expand_debug_expr): Fail if bitpos < 0 for non-MEM op0. + +2009-10-17 Andy Hutchinson + + PR middle-end/41738 + * optabs.c (expand_binop): Make mode of shift count expression mode + of shift count not target. + Remove indent nit. + +2009-10-17 Eric Botcazou + + * tree-nested.c (convert_nonlocal_reference_stmt) : New + case. Force using values to replace references within the statement. + (convert_local_reference_stmt): Likewise. + +2009-10-17 Eric Botcazou + + * gimple-low.c (lower_stmt) : If the call is noreturn, + remove a subsequent GOTO or RETURN statement. + +2009-10-17 Andy Hutchinson + + * config/avr.md (*movqi): Add zero as equally preferable constraint + as general register. + (*movhi): Ditto. + +2009-10-17 Eric Botcazou + + * print-tree.c (print_node): Fix string for DECL_STRUCT_FUNCTION. + +2009-10-17 Richard Guenther + + * lto-streamer-in.c (lto_input_location): Try to reuse previous maps. + +2009-10-17 Richard Guenther + + * lto-streamer-in.c (input_gimple_stmt): Fixup FIELD_DECL + operands in COMPONENT_REFs. + +2009-10-17 Anatoly Sokolov + + * targhooks.c (default_libcall_value): Don't use LIBCALL_VALUE macro + if not defined. Change type of second argument to const_rtx. + (default_function_value): Call gcc_unreachable if FUNCTION_VALUE + macro not defined. + * targhooks.h (default_libcall_value): Update prototype. + * target.h (struct gcc_target): Change type of second argument of + libcall_value to const_rtx. + * config/arm/arm.c (arm_libcall_value): Change type of second argument + to const_rtx. + (arm_libcall_uses_aapcs_base): Change type of argument to const_rtx. + * doc/tm.texi (TARGET_LIBCALL_VALUE): Revise documentation. + +2009-10-17 Jakub Jelinek + + PR debug/40521 + * debug.h (struct gcc_debug_hooks): Add assembly_start hook. + * cgraphunit.c (cgraph_optimize): Call it. + * dwarf2out.c (dwarf2out_init): Move .cfi_sections printing into... + (dwarf2out_assembly_start): ... here. New hook. + (dwarf2out_debug_hooks): Add dwarf2out_assembly_start. + * debug.c (do_nothing_debug_hooks): Do nothing for assembly_start + hook. + * dbxout.c (dbx_debug_hooks, xcoff_debug_hooks): Likewise. + * sdbout.c (sdb_debug_hooks): Likewise. + * vmsdbgout.c (vmsdbg_debug_hooks): Add vmsdbgout_assembly_start. + (vmsdbgout_assembly_start): New hook. + +2009-10-17 Alexandre Oliva + + * rtl.h (RTL_LOCATION): Fix typo. + +2009-10-17 Alexandre Oliva + + * print-rtl.c (print_rtx): Print locators in asm_operands + and asm_input. + +2009-10-17 Alexandre Oliva + + PR debug/41535 + * sched-deps.c (depl_on_debug_p): New. + (attach_dep_link): Reject debug deps before nondebug deps. + (add_to_deps_list): Insert debug deps after nondebug deps. + (sd_lists_empty_p): Stop at first nonempty list. Disregard debug + deps. + (sd_add_dep): Do not reject debug deps. + (add_insn_mem_dependence): Don't count debug deps. + (remove_from_deps): Likewise. + (sched_analyze_2): Set up mem deps on debug insns. + (sched_analyze_insn): Record reg uses for deps on debug insns. + * haifa-sched.c (schedule_insn): Reset deferred debug insn. Don't + try_ready nondebug insn after debug insn. + * ddg.c (create_ddg_dep_from_intra_loop_link, + create_ddg_dep_no_link): Don't reject debug deps. + +2009-10-16 Richard Guenther + + * lto-symtab.c (merge_incomplete_and_complete_type): Remove. + (maybe_merge_incomplete_and_complete_type): Likewise. + (lto_symtab_merge): Do not call them. Do not warn for + complete vs. incomplete compatible types. + (lto_symtab_merge_decls_2): Simplify. + * gimple.c (gimple_force_type_merge): Remove. + (gimple_types_compatible_p): Make it static. + * gimple.h (gimple_force_type_merge): Remove. + (gimple_types_compatible_p): Likewise. + +2009-10-16 Jakub Jelinek + + * dwarf2out.c (mem_loc_descriptor) : Cast + DWARF2_ADDR_SIZE to int to avoid signed vs. unsigned warnings. + +2009-10-16 Richard Guenther + + PR tree-optimization/41728 + * tree-ssa-dom.c (optimize_stmt): Mark the stmt modified + if fold_stmt did anything. + +2009-10-16 Richard Guenther + + PR lto/41715 + * lto-streamer-in.c (lto_input_tree_ref): Revert last change. + (maybe_fixup_handled_component): New function. + (input_gimple_stmt): Fixup mismatched decl replacements. + +2009-10-16 Richard Guenther + + PR lto/41713 + * lto-streamer-out.c (lto_output_tree_ref): Handle DEBUG_EXPR_DECL + the same as VAR_DECL. + +2009-10-16 Richard Guenther + + * gimple.c (iterative_hash_gimple_type): For integer types + also hash their minimum and maximum values and the string flag. + For array types hash their domain and the string flag. + +2009-10-16 Richard Guenther + + * gimple.c (gimple_types_compatible_p): Restrict completing + types to record or unions. Simplify completion. + Do not merge records or unions with different + TYPE_STRUCTURAL_EQUALITY_P tag. + (iterative_hash_gimple_type): Restrict non-recursing into + pointer targets for records and unions. + +2009-10-15 Jakub Jelinek + + PR debug/41717 + * cfgexpand.c (expand_debug_expr): Handle CONJ_EXPR. + * dwarf2out.c (mem_loc_descriptor): Don't handle + POST_INT/POST_DEC/POST_MODIFY like SUBREG. For SUBREG + punt if it is not lowpart subreg or if inner mode isn't + MODE_INT. + +2009-10-16 Andreas Krebbel + + * config/s390/s390.c (s390_z10_optimize_cmp): Skip notes when + investigating previous or next insns. + +2009-10-16 Eric Botcazou + + * tree-sra.c (build_ref_for_offset_1): Update comment. + +2009-10-16 Wolfgang Gellerich + + * config/s390/s390.md (atype): Added missing values. + +2009-10-15 John David Anglin + + PR target/41702 + * pa.md (casesi): Use sign extended index in call to gen_casesi64p. + (casesi64p): Update pattern to reflect above. + +2009-10-15 Steve Ellcey + + PR rtl-optimization/41697 + * sel-sched-ir.h (_eligible_successor_edge_p): Check successor count. + +2009-10-15 Michael Meissner + + PR target/23983 + * config/rs6000/predicates.md: Update copyright year. + * config/rs6000/altivec.md: Ditto. + + * config/rs6000/t-rs6000 (TM_H): Add rs6000-builtin.def. + (MD_INCLUDES): Add a2.md. + + * config/rs6000/rs6000.c (rs6000_builtin_decls): Change + RS6000_BUILTIN_COUNT to MAX_RS6000_BUILTINS. + (builtin_classify): New static vector to classify various builtins + to get the tree attributes correct. + (def_builtin): Set the attributes of builtins based on what the + builtin does (i.e. memory operation, floating point, saturation + need special attributes, others are pure functions). + + * config/rs6000/rs6000.h (enum rs6000_btc): New enum to classify + the builtins. + (enum rs6000_builtins): Include rs6000-builtin.def to define the + builtins. Change the end marker to MAX_RS6000_BUILTINS from + RS6000_BUILTIN_COUNT. + (rs6000_builtin_decls): Change RS6000_BUILTIN_COUNT to + MAX_RS6000_BUILTINS. + + * config/rs6000/rs6000-builtin.def: New file that combines the + builtin enumeration name and attributes. + +2009-10-15 H.J. Lu + + * config/i386/linux.h (ASM_SPEC): Add --32. + +2009-10-15 Jakub Jelinek + + * dwarf2out.c (dwarf_tag_name): Handle DW_TAG_rvalue_reference_type + and DW_TAG_template_alias. + (dwarf_attr_name): Handle DW_AT_main_subprogram, + DW_AT_data_bit_offset, DW_AT_const_expr, DW_AT_enum_class, + DW_AT_linkage_name, DW_AT_GNU_guarded_by, DW_AT_GNU_pt_guarded_by, + DW_AT_GNU_guarded, DW_AT_GNU_pt_guarded, DW_AT_GNU_locks_excluded, + DW_AT_GNU_exclusive_locks_required, DW_AT_GNU_shared_locks_required + and DW_AT_GNU_odr_signature. + (dwarf_form_name): Handle DW_FORM_sec_offset, DW_FORM_exprloc, + DW_FORM_flag_present and DW_FORM_ref_sig8. + (output_signature): Only print name on the first byte. + (output_die): Likewise for dw_val_class_data8. + +2009-10-15 Alexander Monakov + + * doc/invoke.texi: Clarify that most optimizations are not enabled + without -O. + +2009-10-15 Richard Guenther + + PR lto/41668 + * gimple.c (compare_type_names_p): Handle anonymous names + differently based on new mode argument. + (gimple_types_compatible_p): For structs also compare the tags. + (iterative_hash_type_name): Rename to ... + (iterative_hash_name): ... this. Hash all names. + (iterative_hash_gimple_type): Fix hashing the struct tag of + pointer targets. Hash field decl names. + +2009-10-15 Richard Guenther + + PR lto/41669 + * gimple.c (gimple_get_alias_set): Avoid recursing on + invalid type topology. + +2009-10-15 Andrew Pinski + + * config/spu/spu.c (get_branch_target): Use extract_asm_operands. + +2009-10-15 Richard Guenther + + * tree.c (free_lang_data_in_decl): Free DECL_FCONTEXT. + +2009-10-15 Jakub Jelinek + + * config/rs6000/option-defaults.h (OPTION_DEFAULT_SPECS): Don't + add --with-tune{,-32,-64} configured default for -mtune if explicit + -mcpu is used. + +2009-10-14 Daniel Gutson + + * config/arm/neon.md (neon_vshll_n): Checking Bounds fixed. + +2009-10-14 DJ Delorie + + * config/h8300/h8300.c (F): New. + (Fpa): New. + (h8300_emit_stack_adjustment): Call them. + (push): Likewise. + (h8300_push_pop): Likewise. + (h8300_expand_prologue): Likewise. + * config/h8300/h8300.h (DWARF2_DEBUGGING_INFO): Define. + (MUST_USE_SJLJ_EXCEPTIONS): Define. + (INCOMING_RETURN_ADDR_RTX): Define. + (INCOMING_FRAME_SP_OFFSET): Define. + (DWARF_CIE_DATA_ALIGNMENT): Define. + +2009-10-14 Jakub Jelinek + + * stor-layout.c (place_field): Don't emit -Wpadded warnings for + fields in builtin structs. + (finalize_record_size): Likewise. + +2009-10-14 Richard Guenther + + * gimple.c (gtc_ob): New global. + (struct type_pair_d): Replace pointers with type UIDs. + (type_pair_hash): Adjust. + (type_pair_eq): Likewise. + (lookup_type_pair): Likewise. Allocate from an obstack. + (gimple_force_type_merge): Adjust. + (gimple_types_compatible_p): Likewise. + (free_gimple_type_tables): Free the obstack. + +2009-10-14 Jakub Jelinek + + * tree-parloops.c (separate_decls_in_region_debug_bind): Drop debug + stmts setting DEBUG_EXPR_DECLs. + + * cfgexpand.c (expand_debug_expr): Ignore zero-length bitfields. + Don't crash if mode1 is VOIDmode. + +2009-09-26 Vladimir Makarov + + * params.def (PARAM_IRA_LOOP_RESERVED_REGS): New. + * params.h (IRA_LOOP_RESERVED_REGS): New. + * tree-pass.h (pass_subregs_of_mode_init, + pass_subregs_of_mode_finish): Remove. + * passes.c (pass_subregs_of_mode_init, + pass_subregs_of_mode_finish): Remove. + (pass_reginfo_init): Move before loop optimizations. + * config/i386/i386.h (STACK_REG_COVER_CLASS): Define. + * common.opt (fira-loop-pressure): New. + * toplev.h (flag_ira_loop_pressure): New. + * rtl.h (init_subregs_of_mode, finish_subregs_of_mode): New externals. + * reginfo.c (init_subregs_of_mode, finish_subregs_of_mode): + Make external and void type functions. + (gate_subregs_of_mode_init, pass_subregs_of_mode_init, + pass_subregs_of_mode_finish): Remove. + * ira-costs.c (init_costs): Call init_subregs_of_mode. + * regmove.c: Include ira.h. + (regmove_optimize): Call ira_set_pseudo_classes after IRA based + register pressure calculation in loops. + * loop-invariant.c: Include REGS_H and ira.h. + (struct loop_data): New members max_reg_pressure, regs_ref, and + regs_live. + (struct invariant): New member orig_regno. + (curr_loop): New variable. + (find_exits): Initialize regs_ref and regs_live. + (create_new_invariant): Initialize orig_regno. + (get_cover_class_and_nregs): New. + (get_inv_cost): Make aregs_needed an array. Use regs_needed as an + array. Add code for flag_ira_loop_pressure. + (gain_for_invariant): Make new_regs an array. Add code for + flag_ira_loop_pressure. + (best_gain_for_invariant): Ditto. + (set_move_mark): New parameter gain. Use it for debugging output. + (find_invariants_to_move): Make regs_needed and new_regs an array. + Add code for flag_ira_loop_pressure. + (move_invariant_reg): Set up orig_regno. + (move_invariants): Set up reg classes for pseudos for + flag_ira_loop_pressure. + (free_loop_data): Clear regs_ref and regs_live. + (curr_regs_live, curr_reg_pressure, regs_set, n_regs_set, + get_regno_cover_class, change_pressure, mark_regno_live, + mark_regno_death, mark_reg_store, mark_reg_clobber, + mark_reg_death, mark_ref_regs, calculate_loop_reg_pressure): New. + (move_loop_invariants): Calculate pressure. Initialize curr_loop. + * ira.c (ira): Call ira_set_pseudo_classes after IRA based + register pressure calculation in loops if new regs were added. + Call finish_subregs_of_mode. + * opts.c (decode_options): Set up flag_ira_loop_pressure. + * Makefile.in (loop-invariant.o): Add ira.h. + (regmove.o): Ditto. + * doc/invoke.texi (-fira-loop-pressure, ira-loop-reserved-regs): + Describe. + * doc/tm.texi (STACK_REG_COVER_CLASS): Describe. + +2009-10-14 Richard Guenther + + * lto-symtab.c (lto_symtab_compatible): Fold in ... + (lto_symtab_merge): ... here. Rewrite both to take the + prevailing and a to-be-merged entry and to queue diagnostics properly. + (lto_symtab_resolve_replaceable_p): New predicate for + symbol resolution. + (lto_symtab_resolve_can_prevail_p): Likewise. + (lto_symtab_resolve_symbols): Rewrite. Fold in code that + handles merging commons by choosing the largest decl. Fold + in code that gives ODR errors. + (lto_symtab_merge_decls_2): Simplify a lot. Emit queued + diagnostics here. + (lto_symtab_merge_decls_1): Re-structure. Deal with the + case of no prevailing decl here. Diagnose mismatches + in object types here. Drop all but the prevailing decls. + (lto_symtab_prevailing_decl): Return the single prevailing decl. + * lto-streamer-in.c (lto_input_tree_ref): Deal with + VIEW_CONVERT_EXPRs in decl slots. Unshare the tree in this case. + +2009-10-14 Richard Guenther + + PR lto/41521 + * lto-streamer-in.c (input_bb): Replace debug stmts with + nops instead of dropping them. + +2009-10-14 Nick Clifton + + * gcc/doc/extended.texi: Replace the dash character with @minus{} + in situations where it is being used as a minus symbol. + * gcc/doc/tm.texi: Likewise. + * gcc/doc/md.texi: Likewise. + +2009-10-14 Jakub Jelinek + + PR preprocessor/41543 + * input.h (BUILTINS_LOCATION): Change to 1 from 2. + Assert BUILTINS_LOCATION < RESERVED_LOCATION_COUNT. + * tree.c: Include intl.h. + (expand_location): Handle BUILTINS_LOCATION. + * Makefile.in (tree.o): Depend on intl.h. + + PR debug/41695 + * dwarf2out.c (dwarf2out_var_location): Always clear + last_postcall_label when changing last_label. + +2009-10-14 Pascal Obry + + * gcc.c (DEFAULT_SWITCH_CURTAILS_COMPILATION): Add -E. + (process_command): Handle -E as done with -c and -S. Do not add + the target executable suffix to the output file when -E is used. + (main): Adjust error message accordingly. + +2009-10-14 Alexandre Oliva + + PR debug/41343 + PR debug/41447 + PR debug/41264 + PR debug/41338 + * tree.c (tree_node_structure_for_code): DEBUG_EXPR_DECL uses + decl with rtl. + (tree_code_size): Likewise. + +2009-10-13 Kaveh R. Ghazi + + * builtins.c (fold_builtin_1): Support complex "arc" functions. + * real.h (HAVE_mpc_arc): Define. + +2009-10-14 Kaz Kojima + + * config/sh/sh.c (TARGET_BUILTIN_DECL): Define. + (struct builtin_description): Add fndecl field. + (bdesc): Remove const qualifier. Update initializer. + (sh_media_init_builtins): Remove const qualifier for d. Record + the result of add_builtin_function to the fndecl field. + (sh_builtin_decl): New. + (sh_media_builtin_decl): New. + +2009-10-14 Hans-Peter Nilsson + + PR target/38948 + * config/cris/cris.h (SECONDARY_RELOAD_CLASS): Handle reload + requests between special registers. + +2009-10-13 Eric Botcazou + + * dwarf2out.c (mem_loc_descriptor): Accept UNGT as well. + +2009-10-13 Richard Henderson + + PR tree-optimization/41377 + * tree-eh.c (unsplit_eh): Propagate degenerate PHIs. + (cleanup_empty_eh_merge_phis): New change_region parameter; + pass it on to redirect_eh_edge_1. Update callers. + (cleanup_empty_eh_unsplit): Don't require an existing EH label + at the destination block. + +2009-10-13 Basile Starynkevitch + + * passes.c (register_pass): Replaced gcc_unreachable by + fatal_error on failure. Mentions plugins in comments & messages. + +2009-10-13 Jakub Jelinek + + PR target/41693 + * rtl.h (DEBUG_EXPR_TREE_DECL): Define. + * sched-vis.c (print_value): Use it. + * cselib.c (cselib_hash_rtx): Likewise. + * print-rtl.c (print_rtx): Likewise. + * cfgexpand.c (expand_debug_rtx): Likewise. + * var-tracking.c (vt_expand_loc_callback): Likewise. + +2009-10-13 Richard Guenther + + PR lto/41565 + * opts.c (handle_option): Split out code to handle setting + the options flag var ... + (set_option): ... here. + * opts.h (set_option): Declare. + * lto-opts.c (register_user_option_p): Include -fexceptions + and all position independent code variants. + (handle_common_option): Remove. + (lto_reissue_options): Use set_option. + +2009-10-13 Martin Jambor + + PR tree-optimization/41661 + * ipa-prop.c (compute_complex_pass_through): Allow only operations + that are tcc_comparisons or do not change the type in any + un-usleless way. + * ipa-cp.c (ipcp_lattice_from_jfunc): Request boolean type when + folding tcc_comparison operations. + +2009-10-13 Andreas Krebbel + + * config/s390/s390.c (s390_encode_section_info): Handle BLKmode + properly. + +2009-10-12 Alexandre Oliva + + PR debug/41343 + PR debug/41447 + PR debug/41264 + PR debug/41338 + * tree.def (DEBUG_EXPR_DECL): New. + * rtl.def (DEBUG_EXPR): New. + * gengtype.c (adjust_field_rtx_def): Handle it. + * tree-ssa.c (propagate_var_def_into_debug_stmts): Rename to... + (insert_debug_temp_for_var_def): ... this. Drop support for + moving. Take iterator for def stmt; insert debug stmt before it. + Scan early for use count and kind in debug stmts. + (propagate_defs_into_debug_stmts): Rename to... + (insert_debug_temps_for_defs): ... this. Likewise. + * tree.h (DEBUG_TEMP_UID): New. + * tree.c (next_debug_decl_uid): New. + (make_node_stat): Count debug decls separately. + (copy_node_stat): Likewise. + * cfgexpand.c (expand_debug_expr): Handle DEBUG_EXPR_DECL. + * var-tracking.c (dv_is_decl_p): Recognize it. + (VALUE_RECURSED_INTO): Apply to DEBUG_EXPRs too. + (track_expr_p): Track expanded DEBUG_EXPR_DECLs. + (vt_expand_loc_callback): Expand DEBUG_EXPRs. + (emit_note_insn_var_location): Don't emit notes for DEBUG_EXPR_DECLs. + * cselib.c (rtx_equal_for_cselib_p): Handle DEBUG_EXPR. + (cselib_hash_rtx): Likewise. + (cselib_expand_value_rtx_1): Use callback for DEBUG_EXPR. + * tree-ssa-operands.c (get_expr_operands): Skip DEBUG_EXPR_DECLs in + debug bind stmts. + * emit-rtl.c (verify_rtx_sharing): Handle DEBUG_EXPR and VALUE. + (copy_rtx_if_shared_1, reset_used_flags, set_used_flags): Likewise. + * rtl.c (copy_rtx): Likewise. + (rtx_equal_p_cb, rtx_equal_p): Handle DEBUG_EXPR. + * print-rtl.c (print_rtx): Likewise. + * sched-vis.c (print_value): Likewise. + (print_insn): Handle DEBUG_EXPR_DECL. + * tree-dump.c (dequeue_and_dump): Likewise. + * tree-pretty-print.c (dump_decl_name, dump_generic_node): Likewise. + * gimple-iterator (gsi_replace): Check for same lhs. + (gsi_remove): Insert debug temps. + * tree-ssa-loop-im.c (rewrite_reciprocal): Replace with same lhs. + (move_computations_stmt): Drop explicit propagation into debug stmts. + (rewrite_bittest): Likewise. Use gsi_remove for propagation. + * tree-ssa-reassoc.c (rewrite_expr_tree, linearize_expr): Likewise. + * tree-ssa-sink.c (statement_sink_location): Likewise. + * tree-ssa-forwprop (forward_propagate_addr_expr): Likewise. + * tree-ssanames.c (release_ssa_name): Adjust for rename. + * tree-flow.h: Likewise. + * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Don't mark + debug temps without values. + (eliminate_unnecessary_stmts): Don't discard just-inserted + debug stmts. + +2009-10-12 Hans-Peter Nilsson + + PR target/26515 + * config/cris/cris.md (andu): Check that operand 1 is one of the + general registers. Fix typo in head comment. + +2009-10-12 Stefan Dösinger + + * config/i386/i386.md (vswapmov): New. + * config/i386/i386.c (ix86_handle_fndecl_attribute): New. + (ix86_function_ms_hook_prologue): New. + (ix86_expand_prologue): Handle ms_hook_prologue attribute. + * configure.ac: Test for swap suffix support in as. + * configure: Rebuild. + +2009-10-12 Jakub Jelinek + + PR target/41680 + * config/i386/i386.md (split after *testqi_ext_3_rex64): Only narrow + paradoxical subregs to prevent partial register stalls if the inner + mode is integer mode. + +2009-10-12 Uros Bizjak + + * config/i386/i386.md (*setcc__2): Remove insn pattern. + +2009-10-12 Dodji Seketeli + + PR c++/41570 + * gcc/dwarf2out.c (template_parameter_pack_die, + gen_formal_parameter_pack_die): Use add_name_and_src_coords_attributes. + +2009-10-12 Alexandre Oliva + + PR debug/41616 + * tree-into-ssa.c (insert_phi_nodes_for): Build debug bind stmts + on updates too. + (maybe_register_def): Likewise. Take stmt iterator. + (rewrite_update_stmt): Take stmt iterator and pass it on. + (rewrite_update_enter_block): Pass stmt iterator. + +2009-10-11 Andrew Pinski + + * config/spu/spu.c (TARGET_BUILTIN_DECL): Define. + (spu_builtin_decl): New function. + +2009-10-12 Uros Bizjak + + * config/i386/i386.md (SWIM): New mode iterator. + (movcc): Macroize expander from mov{qi,hi,si,di}cc patterns + using SWIM mode iterator. + (x86_movcc_0_m1): Macroize insn from x86_mov{si,di}cc_0_m1 + patterns using SWI48 mode iterator. + (*x86_movcc_0_m1_se): Macroize insn from + *x86_mov{si,di}cc_0_m1_se patterns using SWI48 mode iterator. + (*x86_movcc_0_m1_neg): New insn pattern. + (*movcc_noc): Macroize insn from *mov{hi,si,di}cc_noc + patterns using SWI248 mode iterator. + * config/i386/i386.c (ix86_expand_int_movcc): Update the call to + gen_x86_movdicc_0_m1_rex64 for renamed function + +2009-10-11 Jose Ruiz + Eric Botcazou + + PR target/33743 + * config/sparc/sol2.h (MD_UNWIND_SUPPORT): Define. + * config/sparc/sol2-unwind.h: New file. + +2009-10-11 Olivier Hainque + Eric Botcazou + + PR target/33743 + * config/i386/sol2.h (MD_UNWIND_SUPPORT): Define. + * config/i386/sol2-unwind.h: New file. + +2009-10-11 H.J. Lu + + PR target/41665 + * config/i386/i386.md (addsi_1_zext): Get the proper second + operand for lea. + +2009-10-11 Richard Sandiford + + * simplify-rtx.c (simplify_replace_rtx): Use rtx_equal_p for + all OLD_RTXes, not just REGs. Use copy_rtx to create the + replacement value. + +2009-10-11 Richard Guenther + + * gimple.c (iterative_hash_type_name): Do not handle special + anonymous names. + +2009-10-11 Uros Bizjak + + * config/i386/i386.md (*setcc_di_1): New insn_and_split pattern. + (*setcc_si_1_and): Ditto. + (*setcc_si_1_movzbl): Ditto. + (*setcc__2): Ditto. + (*setcc_qi): Rename from *setcc_1. + (*setcc_qi_slp): Rename from *setcc_2. + + (*zero_extendqihi2_movzbw_and splitter): Use ix86_expand_clear. + (*zero_extendqisi2_movzbw_and splitter): Ditto. + + * config/i386/i386.c (ix86_expand_clear): Remove reload_completed from + "if" condition, there is already assert with reload_completed present. + +2009-10-11 Gerald Pfeifer + + * plugin.c (try_init_one_plugin): Improve constness of variable err. + +2009-10-10 Gerald Pfeifer + + * doc/install.texi (Final install): Refer to + http://gcc.gnu.org/bugs/ for bug reporting. + +2009-10-10 Peter Bergner + + * configure.ac: Add test for dci instruction. + * configure: Regenerate. + * config.in: Likewise. + * config.gcc: Handle --with-cpu=476 and --with-cpu=476fp. + * doc/invoke.texi: Add cpu_type 476 and 476fp. + (-mmulhw): Add 476 to description. + (-mdlmzb): Likewise. + * config/rs6000/t-fprules (MULTILIB_MATCHES_FLOAT): Include -mcpu=476. + * config/rs6000/rs6000.c (processor_costs): Add ppc476_cost. + (processor_target_table): Add 476 and 476fp entries. + (rs6000_override_options): Use ppc476_cost for PROCESSOR_PPC476. + (rs6000_issue_rate): Add CPU_PPC476. + * config/rs6000/rs6000.h (ASM_CPU_476_SPEC): Define. + (ASM_CPU_SPEC): Pass %(asm_cpu_476) for -mcpu=476 and -mcpu=476fp. + (processor_type): Add PROCESSOR_PPC476. + (EXTRA_SPECS): Add asm_cpu_476 string. + * config/rs6000/rs6000.md (define_attr "type"): Add isel attribute. + (define_attr "cpu"): Add ppc476. + Include 476.md. + Update comments for 476. + (isel_signed, isel_unsigned): Change to use "isel" type attribute. + * config/rs6000/vxworks.h (CPP_SPEC): Handle 464 and 476. + Update copyright year. + * config/rs6000/476.md: New file. + * config/rs6000/40x.md: Add description for "isel" attribute. + Update copyright year. + * config/rs6000/440.md: Likewise. + * config/rs6000/603.md: Likewise. + * config/rs6000/6xx.md: Likewise. + * config/rs6000/7450.md: Likewise. + * config/rs6000/7xx.md: Likewise. + * config/rs6000/8540.md: Likewise. + * config/rs6000/cell.md: Likewise. + * config/rs6000/e300c2c3.md: Likewise. + * config/rs6000/e500mc.md: Likewise. + * config/rs6000/mpc.md: Likewise. + * config/rs6000/power4.md: Likewise. + * config/rs6000/power5.md: Likewise. + * config/rs6000/power6.md: Likewise. + * config/rs6000/power7.md: Likewise. + * config/rs6000/rios1.md: Likewise. + * config/rs6000/rios2.md: Likewise. + * config/rs6000/rs64.md: Likewise. + +2009-10-10 Richard Guenther + + PR tree-optimization/41654 + * tree-ssa-ifcombine.c (ifcombine_ifandif): Properly canonicalize + a cond expr before calling gimple_cond_set_condition_from_tree. + (ifcombine_iforif): Likewise. + +2009-10-09 Ian Lance Taylor + + * configure.ac: Use AC_SEARCH_LIBS to find dlopen. + * configure: Rebuild. + +2009-10-09 Neil Vachharajani + + * doc/cpp.texi (Other Directives): Do not list #ident and #sccs as + deprecated. + +2009-10-09 Richard Guenther + + PR lto/41638 + * target-def.h (TARGET_BUILTIN_DECL): Define. + (TARGET_INITIALIZER): Add TARGET_BUILTIN_DECL. + * target.h (struct gcc_target): Add builtin_decl target hook. + * doc/tm.texi (TARGET_BUILTIN_DECL): Document. + * lto-streamer-in.c (lto_get_builtin_tree): Fix handling of + target builtins. + * lto-streamer-out.c (lto_output_tree_pointers): Use sorry, + not gcc_unreachable. + (lto_output_builtin_tree): Sorry if the target does not support + streaming target builtins. + * config/rs6000/rs6000.c (TARGET_BUILTIN_DECL): Define. + (rs6000_builtin_decl): New function. + * config/i386/i386.c (TARGET_BUILTIN_DECL): Define. + (ix86_builtin_decl): New function. + +2009-10-09 Jakub Jelinek + + PR preprocessor/41445 + * c-ppoutput.c (do_line_change): New function. + (cb_line_change): Use it. + (scan_translation_unit): Call do_line_change if + avoid_paste or PREV_WHITE and token location is on a different line + than print.src_line. + + PR debug/40521 + * dwarf2out.c (dwarf2out_init): Test whether + HAVE_GAS_CFI_SECTIONS_DIRECTIVE is non-zero instead of checking + it is defined. + + PR rtl-optimization/41646 + * calls.c (expand_call): For BLKmode types returned in registers + avoid likely spilled hard regs in copy_blkmode_from_reg generated + insns. + +2009-10-09 Richard Guenther + + PR tree-optimization/41634 + * tree-ssa-dom.c (remove_local_expressions_from_table): Assert + we remove the correct elements. + (optimize_stmt): Make sure to update stmt operands before + optimizing redundancies. + +2009-10-09 Andreas Krebbel + + * config/s390/s390.md ("prefetch"): Remove stcmh for prefetching. + +2009-10-09 Richard Guenther + + PR driver/41637 + * lto-wrapper.c (ltrans_output_file, flto_out, args_name): New + globals. + (lto_wrapper_exit): New function. + (fatal): Use it. + (fatal_perror): Likewise. + (fork_execute): Use global args_name, do not free it. + (run_gcc): Use global ltrans_output_file, flto_out, do not free them. + * lto-streamer.h: Remove duplicate prototypes. + +2009-10-09 Richard Guenther + + * cgraph.c (cgraph_create_edge): Check for NULL call_stmt + before calling stmt_can_throw_external. + +2009-10-09 Eric Botcazou + + PR tree-optimization/40071 + * tree-vect-data-refs.c (vect_create_data_ref_ptr): Build a ref-all + pointer if the original data reference doesn't conflict with the + created vector data reference. Fix long line. + +2009-10-09 Uros Bizjak + + * config/i386/i386.md (any_div): New code iterator. + (u): Handle div and udiv. + (sgnprefix): Ditto. + (divqi3): Macroize insn from {,u}divqi3 using any_div + code iterator. + (lfloor2): Macroize insn from + lfloor{si,di}2 patterns using SWI48 mode iterator. + (lceil2): Macroize insn from + lceil{si,di}2 patterns using SWI48 mode iterator. + +2009-10-08 Joseph Myers + + * gcc.c (main): Remove trailing "." from diagnostics. + +2009-10-08 Cary Coutant + + Add support for debugging with ICF (Identical Code Folding). + * calls.c (debug.h): New #include. + (emit_call_1): Call virtual_call_token debug hook. + * common.opt (-fenable-icf-debug): New option. + * dwarf2out.c (dwarf2_debug_hooks): Add entries for new hooks (two + locations in the source). + (poc_label_num): New variable. + (dcall_entry, vcall_entry): New typedefs. + (dcall_table, vcall_table): New variables. + (struct vcall_insn): New type. + (vcall_insn_table): New variable. + (DEBUG_DCALL_SECTION, DEBUG_VCALL_SECTION): New macros. + (size_of_dcall_table): New function. + (output_dcall_table): New function. + (size_of_vcall_table): New function. + (output_vcall_table): New function. + (dwarf2out_direct_call): New function. + (vcall_insn_table_hash): New function. + (vcall_insn_table_eq): New function. + (dwarf2out_virtual_call_token): New function. + (dwarf2out_virtual_call): New function. + (dwarf2out_init): Allocate new tables and sections. + (prune_unused_types): Mark DIEs referenced from direct call table. + (dwarf2out_finish): Output direct and virtual call tables. + * final.c (final_scan_insn): Call direct_call and virtual_call + debug hooks. + * debug.h (struct gcc_debug_hooks): Add direct_call, + virtual_call_token, virtual_call hooks. + (debug_nothing_uid): New function. + * debug.c (do_nothing_debug_hooks): Add dummy entries for new hooks. + (debug_nothing_uid): New function. + * dbxout.c (dbx_debug_hooks): Add dummy entries for new hooks. + (xcoff_debug_hooks): Likewise. + * sdbout.c (sdb_debug_hooks): Likewise. + * vmsdbgout.c (vmsdbg_debug_hooks): Likewise. + * doc/invoke.texi (-fenable-icf-debug): New option. + +2009-10-08 Alexandre Oliva + + PR debug/41353 + * regmove.c (regmove_backward_pass): Replace src with dst in the + debug insn, and check for dst before rather than after. + +2009-10-08 Janis Johnson + + * config/rs6000/rs6000.c (rs6000_delegitimize_address): Remove. + (TARGET_DELEGITIMIZE_ADDRESS): Likewise. + +2009-10-08 Jan Hubicka + + PR middle-end/41626 + * cgraphbuild.c (record_reference): When parameter DATA is NULL, + do not mark cgraph nodes as needed. + (record_references_in_initializer): Add new only_vars parameter. + * cgraph.h (record_references_in_initializer): New parameter. + * varasm.c (assemble_variable): Update call. + * varpool.c (varpool_analyze_pending_decls): Always look for + referenced vars. + +2009-10-08 Anatoly Sokolov + + * config/avr/avr.c (last_insn_address) Remove variable. + (expand_prologue): Don't initialise last_insn_address variable. + (final_prescan_insn): Don't output insn size. + * config/avr/avr.opt (msize): Remove switch. + * doc/invoke.texi (AVR Options): Remove documentation of -msize + switch. + +2009-10-08 Adam Nemet + + * combine.c (label_tick_ebb_start): Fix comment. + (combine_instructions): Set label_tick and label_tick_ebb_start before + calling setup_incoming_promotions. Start them from 1. Increment + label_tick instead of deriving it from the BB index. Rather than + comparing ticks use the block from the previous iteration to decide + whether to start a new EBB. Remove empty lines before function. + +2009-10-08 Michael Matz + + PR middle-end/41573 + * builtins.c (fold_builtin_isascii): Use fold_build2. + (fold_builtin_isdigit): Ditto. + * except.c (duplicate_eh_regions_1): Tolerate NULL labels. + * tree-cfg.c (struct rus_data, remove_useless_stmts_warn_notreached, + remove_useless_stmts_cond, remove_useless_stmts_tf, + remove_useless_stmts_tc, remove_useless_stmts_bind, + remove_useless_stmts_goto, remove_useless_stmts_label, + remove_useless_stmts_1, remove_useless_stmts, + pass_remove_useless_stmts): Remove. + * tree-pass.h (pass_remove_useless_stmts): Don't declare. + * passes.c (init_optimization_passes): Don't add + pass_remove_useless_stmts. + * tree-eh.c (lower_eh_constructs_2): Handle empty cleanups. + * tree.c (free_lang_data_in_decl): Don't clear DECL_INITIAL of + static constants. + * lto-symtab.c (lto_symtab_register_decl): Accepts DECL_INITIAL + for static constants. + * lto-streamer-out.c (output_gimple_stmt): Handle GIMPLE_NOP. + * lto-streamer-in.c (input_gimple_stmt): Handle GIMPLE_NOP. + +2009-10-08 Richard Guenther + + * gimple.c (free_gimple_type_tables): New function. + * gimple.h (free_gimple_type_tables): Declare. + +2009-10-07 Mark Heffernan + + * ipa-prop.c (ipa_print_node_params) Only print + names of named arguments. + +2009-10-08 Rafael Avila de Espindola + + * gcc.c (LINK_COMMAND_SPEC): Pass libc with -pass-through if it is + being statically linked. + +2009-10-08 Rainer Orth + + * collect2.c (add_lto_object): Only define if OBJECT_FORMAT_NONE. + +2009-10-08 Jan Hubicka + + PR bootstrap/41620 + * ipa.c (cgraph_externally_visible_p, + function_and_variable_visibility, + whole_program_function_and_variable_visibility): Skip non-finalized + nodes. + +2009-10-08 Nick Clifton + + * config/mn10300/mn10300.h (CONSTANT_ADDRESS_P): Do not allow + CONST_DOUBLEs. + +2009-10-08 Andreas Tobler + + PR bootstrap/37739 + * config.host: Use config/x-cflags-O1 for powerpc FreeBSD. + +2009-10-07 Joseph Myers + + PR c/41182 + * c-common.c (c_fully_fold_internal): Strip nops from the result + of recursive calls to c_fully_fold_internal. + (c_wrap_maybe_const): New. + (c_save_expr): Use c_wrap_maybe_const. + * c-common.h (c_wrap_maybe_const): Declare. + * c-typeck.c (build_conditional_expr, c_finish_stmt_expr, + build_binary_op): Use c_wrap_maybe_const. + +2009-10-07 Kaveh R. Ghazi + + * real.c: Fix comment to reflect actual exponent size. + +2009-10-08 Ben Elliston + + * config/rs6000/a2.md: Add FSF comment header. + +2009-10-07 Uros Bizjak + + * config/i386/i386.md (any_extend): New code iterator. + (u, s): New code attributes. + (sgnprefix): Ditto. + (DWIH): Rewrite as code iterator for SI and DI modes. + (DWI): Rewrite as mode attribute. + (dwi): New mode attribute. + (di): Depend on SI mode and DI mode. + (doubleint_general_operand): Remove mode attribute. + + (*lea_1): Macroize insn from *lea_1_rex64 and *lea_1 patterns using + DWIH mode iterator. + + (*add3_doubleword): Use DWIH as the base mode iterator. + (*sub3_doubleword): Ditto. + + (mul3): Macroize expander from mul{hi,si,di}3 patterns + using SWIM248 mode iterator. + (*mul3_1): Macroize insn from mul{si,di}3_1 patterns + using SWI48 mode iterator. + (mul3): Macroize expander from {,u}mul{sidi,diti}3 + patterns using DWIH mode iterator and any_extend code iterator. + (mulqihi3): Macroize expander from {,u}mulqihi3 patterns + using any_extend code iterator. + (*mul3_1): Macroize insn from {,u}mul{sidi,diti}3_1 + patterns using DWIH mode iterator and any_extend code iterator. + (*mulqihi3_1): Macroize insn from {,u}mulqihi3_1 patterns + using any_extend code iterator. + (mul3_highpart): Macroize expander from + {s,u}mul{si,di}3_highpart patterns using DWIH mode iterator + and any_extend code iterator. + (*muldi3_highpart_1): Macroize insn from + *{s,u}muldi3_highpart_rex64 patterns using any_extend code iterator. + (*mulsi3_highpart_1): Macroize insn from *{s,u}mulsi3_highpart_1 + patterns using any_extend code iterator. + (*mulsi3_highpart_zext): Macroize insn from + *{s,u}mulsi3_highpart_zext patterns using any_extend code iterator. + +2009-10-07 Jakub Jelinek + + * dwarf2out.c (tree_add_const_value_attribute_for_decl): Don't add + DW_AT_const_value if VAR_DIE already has DW_AT_abstract_origin + refering to a DIE with DW_AT_const_value. + +2009-10-07 Vladimir Makarov + + PR middle-end/22072 + * ira-lives.c (check_and_make_def_conflict): Process all operands. + +2009-10-06 Jan Hubicka + + * cgraph.c (cgraph_node_can_be_local): Handle externally visible nodes + correctly. + +2009-10-06 Uros Bizjak + + * config/i386/i386.md (*lea_1_rex64, *lea_1, *lea_1_zext, + *lea_2_rex64): Move before *add_1 pattern. + +2009-10-07 Jan Hubicka + + * collect2.c (main): Add -fno-whole-program. + * gcc.c (set_collect_gcc_options): Do not remove whole program here. + +2009-10-07 Jan Hubicka + + * lto-symtab.c (lto_cgraph_replace_node): Assert that inline clones + has no address taken. + * cgraph.c (cgraph_mark_needed_node): Assert that inline clones are + never needed. + (cgraph_clone_node): Clear externally_visible flag for clones. + * cgraph.h (cgraph_only_called_directly_p, + cgraph_can_remove_if_no_direct_calls_p): New predicates. + * tree-pass.h (pass_ipa_whole_program_visibility): Declare. + * ipa-cp.c (ipcp_cloning_candidate_p): Use new predicate. + (ipcp_initialize_node_lattices, ipcp_estimate_growth, + ipcp_insert_stage): Likwise. + * cgraphunit.c (cgraph_decide_is_function_needed): Do not compute + externally_visible flag. + (verify_cgraph_node): Verify that inline clones look right. + (process_function_and_variable_attributes): Do not set + externally_visible flags. + (ipa_passes): Avoid executing small_ipa_passes at LTO stage; they've + been already run. + * lto-cgraph.c (lto_output_node): Assert that inline clones are not + boundaries. + * ipa-inline.c (cgraph_clone_inlined_nodes): Use new predicates; + clear externally_visible when turning into inline clones + (cgraph_mark_inline_edge): Use new predicates. + (cgraph_estimate_growth): Likewise. + (cgraph_decide_inlining): Likewise. + * ipa.c (cgraph_postorder): Likewise. + (cgraph_remove_unreachable_nodes): Likewise; sanity check + that inline clones are not needed. + (cgraph_externally_visible_p): New predicate. + (function_and_variable_visibility): Add whole_program parameter; + always set externally_visible flag; handle COMDAT function + privatization. + (local_function_and_variable_visibility): New function. + (gate_whole_program_function_and_variable_visibility): New function. + (whole_program_function_and_variable_visibility): New function. + (pass_ipa_whole_program_visibility): New function. + * passes.c (init_optimization_passes): Add whole program visibility + pass. + (do_per_function_toporder, function_called_by_processed_nodes_p): Do + not care about needed/reachable flags. + * varpool.c: Include flags.h + (decide_is_variable_needed): When doing LTO assume whole-program mode. + (varpool_finalize_decl): When we are in LTO read-back, all variables + are analyzed. + (varpool_analyze_pending_decls): Skip analyzis of analyzed vars. + +2009-10-07 Andreas Krebbel + + * config/s390/tpf.h (TARGET_DEFAULT): Remove MASK_HARD_FLOAT and + add MASK_HARD_DFP. + +2009-10-07 Andreas Krebbel + + * config.gcc: Don't include the makefile fragments intended for + libgcc. + * config/s390/fixdfdi.h: File removed. + * config/s390/libgcc-glibc.ver: File removed. + * config/s390/s390.h: Remove the fixdfdi.h hack. + * config/s390/t-crtstuff: File moved to libgcc dir. + * config/s390/t-linux: Likewise. + * config/s390/t-tpf: libgcc specific parts removed. + * config/s390/t-linux64: Likewise. + +2009-10-06 Jerry Quinn + + * Makefile.in (lto-wrapper): Use COMPILER and ALL_COMPILERFLAGS. + (lto-compress.o): Likewise. + +2009-10-07 Danny Smith + + PR target/41512 + * config/i386/winnt.c (i386_pe_determine_dllexport_p): Don't propagate + dllexport to class members here. + (i386_pe_determine_dllimport_p): Only check static class data for + definition. + (i386_pe_encode_section_info): Don't recheck DECL_DLLIMPORT_P. + * config/i386/winnt-cxx.c (i386_pe_type_dllimport_p): Only check + functions for vague linkage. + (i386_pe_type_dllexport_p): Fix formatting. + (maybe_add_dllexport) New function. + (i386_pe_adjust_class_at_definition): Use it to propagate dllexport + to class members. + +2009-10-07 Ben Elliston + + * config/rs6000/a2.md: Remove duplicated lines. + +2009-10-07 Ben Elliston + + * config.gcc (powerpc*-*-*): Handle a2. + * config/rs6000/rs6000.md (cpu): Add ppca2. Include "a2.md". + * config/rs6000/a2.md: New file. + * config/rs6000/rs6000.opt (mno-update): New. + (mupdate): Return to using a mask, not a var. + * config/rs6000/rs6000.h (ASM_CPU_SPEC): Add support for a2. + (enum processor_type): Add PROCESSOR_PPCA2. + * config/rs6000/rs6000.c (ppca2_cost): New costs. + (rs6000_override_options): Add "a2" to processor_target_table. + Update rs6000_always_hint logic. Correctly set rs6000_cost for a2. + * doc/invoke.texi (RS/6000 and PowerPC Options): Document -mcpu=a2. + +2009-10-06 Uros Bizjak + + * config/i386/i386.md (float2): + Use explicit gen_truncxfsf2 and gen_truncxfdf2 references to avoid + reference to nonexistent gen_truncxfxf2 function. + +2009-10-06 Uros Bizjak + + * config/i386/i386.md (SWI48, SDWIM, DWI): New mode iterators. + (DWIH, g, di, doubleint_general_operand): New mode attributes. + (general_operand): Handle TI mode. + (add3): Macroize expander from add{qi,hi,si,di,ti}3 patterns + using SDWIM mode iterator. + (*add3_doubleword): New insn_and_split pattern. Macroize + pattern from *add{di,ti}3_1 patterns and corresponding splitters + using DWI mode iterator. + (add3_carry): Macroize insn from add{qi,hi,si,di}3_carry + patterns using SWI mode iterator. + (*add3_cc): Macroize insn from add{si,di}3_cc patterns + using SWI48 mode iterator. + (*add_1): Ditto from add{si,di}_1 patterns. + (*add_2): Ditto from add{si,di}_2 patterns. + (*add_3): Ditto from add{si,di}_3 patterns. + (*add_5): Ditto from add{si,di}_5 patterns. + (sub3): Macroize expander from sub{qi,hi,si,di,ti}3 patterns + using SDWIM mode iterator. + (*sub3_doubleword): New insn_and_split pattern. Macroize + pattern from *sub{di,ti}3_1 patterns and corresponding splitters + using DWI mode iterator. + (sub3_carry): Macroize insn from sub{qi,hi,si,di}3_carry + patterns using SWI mode iterator. + (*sub_1): Ditto from from sub{qi,hi,si,di}_1 patterns. + (*sub_2): Ditto from sub{qi,hi,si,di}_2 patterns. + (*sub_3): Ditto from sub{qi,hi,si,di}_3 patterns. + (xf3): Macroize expander from addxf3 and subxf3 + patterns using plusminus code iterator. + (3): Macroize expander from add3 and + sub3 patterns using plusminus code iterator. + * config/i386/i386.c (override_options): Update the call to + gen_subdi_carry_rex64 for renamed function. + (ix86_expand_int_addcc): Update calls to gen_subdi3_carry_rex64 + and gen_adddi3_carry_rex64 for renamed functions. Use indirect + calls to instruction expanders. + +2009-10-06 Martin Jambor + + PR bootstrap/41395 + * opts.c (decode_options): Run IPA-SRA at -O2. + +2009-10-06 Richard Guenther + + * lto-symtab.c (lto_symtab_entry_hash): Hash strings, not pointers. + +2009-10-06 Tobias Burnus + + PR lto/41591 + * doc/invoke.texi (-flto,-fwhole-program): Make clear that the + -flto and -fwhole-program flags can be combined. + +2009-10-06 Ryan Mansfield + + PR driver/41217 + * gcc.c (process_command): Check that -o argument was specified. + +2009-10-06 Jerry Quinn + + * gimple.c (gimple_type_hash): Use CONST_CAST_TREE to fix compilation. + +2009-10-05 Ralf Wildenhues + + * c.opt (Wjump-misses-init): Fix typo to enable for ObjC. + * doc/invoke.texi (Warning Options): Annotate allowed languages + for -Wunsuffixed-float-constants. + +2009-10-05 Jakub Jelinek + + * dwarf2out.c (modified_type_die): Don't add DW_AT_name to + DW_TAG_{const,volatile}_type if its DW_AT_type already has the + same name and isn't the main variant. + + PR debug/41558 + * dwarf2out.c (loc_by_reference): Removed. + (dw_loc_list_1): New function. + (dw_loc_list): Remove toplev argument, add want_address argument. + Don't look at decl_by_reference_p at all. Use dw_loc_list_1. + (loc_list_from_tree) : Pass want_address rather than + want_address == 2 to dw_loc_list. For successful dw_loc_list + set have_address to 1 only if want_address is not 0. + +2009-10-05 Richard Sandiford + + * config/mips/mips-protos.h (mips_trampoline_code_size): Declare. + * config/mips/mips.h (TRAMPOLINE_SIZE): Redefine as the size of + a code block followed by two pointers. + (TRAMPOLINE_ALIGNMENT): Define to 64 for 32-bit targets too. + * config/mips/mips.c (MIPS_LOAD_PTR): New macro. + (MIPS_MOVE): Likewise. + (MIPS_LUI): Likewise. + (MIPS_JR): Likewise. + (MIPS_BAL): Likewise. + (MIPS_NOP): Likewise. + (mips_asm_trampoline_template): Delete. + (mips_trampoline_code_size): New function. + (mips_trampoline_init): Add shorter sequences for all cases + except Pmode == DImoe && !TARGET_USE_PIC_FN_ADDR_REG. + Calculate the opcodes directly, rather than copying from a template. + Only flush the code part of the trampoline. + (TARGET_ASM_TRAMPOLINE_TEMPLATE): Delete. + +2009-10-05 Richard Sandiford + + * config/mips/mips.h (DWARF_FRAME_RETURN_COLUMN): Replace + GP_REG_FIRST + 31 with RETURN_ADDR_REGNUM. + (INCOMING_RETURN_ADDR_RTX): Likewise. + (FUNCTION_PROFILER): Likewise. Replace GP_REG_FIRST + 1 + with AT_REGNUM. + * config/mips/sdemtk.h (FUNCTION_PROFILER): Replace GP_REG_FIRST + 31 + with RETURN_ADDR_REGNUM. + (MIPS_SAVE_REG_FOR_PROFILING_P): Likewise. + * config/mips/mips.c (mips16_build_call_stub): Replace + GP_REG_FIRST + 31 with RETURN_ADDR_REGNUM, GP_REG_FIRST + 1 + with AT_REGNUM and 31 with RETURN_ADDR_REGNUM. + (mips_print_operand_punctuation): Likewise. + (mips_frame_set): Likewise. + (mips16e_output_save_restore): Likewise. + (mips_cfun_might_clobber_call_saved_reg_p): Likewise. + (mips_save_reg_p): Likewise. + (mips_return_addr): Likewise. + (mips_set_return_address): Likewise. + (mips_direct_save_slot_move_p): Likewise. + (mips_output_function_prologue): Likewise. + (mips_restore_reg): Likewise. + (mips_expand_epilogue): Likewise. + (mips_epilogue_uses): Likewise. + * config/mips/mips.md (RETURN_ADD_REGNUM): Define. + (*mov_ra): Use it instead of a hard-coded 31. + (clear_hazard_): Likewise. + (call_internal): Likewise. + (call_internal_direct): Likewise. + (call_direct_split): Likewise. + (call_value_internal): Likewise. + (call_value_split): Likewise. + (call_value_internal_direct): Likewise. + (call_value_direct_split): Likewise. + (call_value_multiple_internal): Likewise. + (call_value_multiple_split): Likewise. + +2009-10-05 Eric Botcazou + Jakub Jelinek + + PR rtl-optimization/41511 + * combine.c (record_value_for_reg): Pass explicit values as argument + to get_last_value_validate. + (get_last_value_validate): Document INSN parameter. + For non-readonly MEMs, assume they might have been modified if INSN + was in another basic block. + (get_last_value): Minor reformatting. + +2009-10-05 Andrew Pinski + + PR tree-opt/40992 + * final.c (asm_str_count): Split out from asm_insn_count. + * rtl.h (asm_str_count): New prototype. + * tree-inline (estimate_num_insns) : Call + asm_str_count. + +2009-10-05 Sriraman Tallam + + * doc/plugins.texi: Change plugin_pass to register_pass_info. + +2009-10-05 Basile Starynkevitch + Rafael Espindola + + * gengtype.c (write_types): Moved call to write_func_for_structure + into seperate loops. + +2009-10-05 Richard Guenther + + PR lto/41281 + * lto-cgraph.c (output_cgraph): Output toplevel asms. + (input_cgraph_1): Input toplevel asms. + +2009-10-05 Richard Guenther + + PR lto/40902 + * lto-symtab.c (lto_compatible_attributes_p): Remove. + (external_aggregate_decl_p): Likewise. + (lto_symtab_compatible): Re-structure. Remove dead code. + For variables ignore toplevel qualifiers when comparing types. + Issue warnings, not errors for mismatched user-alignment. + +2009-10-05 Richard Guenther + + PR lto/41552 + PR lto/41487 + * lto-symtab.c (struct lto_symtab_base_def): Remove. + (struct lto_symtab_identifier_def): Likewise. + (struct lto_symtab_decl_def): Likewise. + (struct lto_symtab_entry_def): New. + (lto_symtab_identifier_t): Rename to ... + (lto_symtab_entry_t): ... this. + (lto_symtab_decls): Remove. + (lto_symtab_base_hash): Rename to ... + (lto_symtab_entry_hash): ... this. + (lto_symtab_base_eq): Rename to ... + (lto_symtab_entry_eq): ... this. + (lto_symtab_base_marked_p): Rename to ... + (lto_symtab_entry_marked_p): ... this. + (lto_symtab_identifier_marked_p): Remove. + (lto_symtab_decl_marked_p): Likewise. + (lto_symtab_maybe_init_hash_tables): Rename to ... + (lto_symtab_maybe_init_hash_table): ... this. + (lto_symtab_set_resolution_and_file_data): Remove. + (lto_symtab_register_decl): New function. + (lto_symtab_get_identifier): Remove. + (lto_symtab_get): New function. + (lto_symtab_get_resolution): Adjust. + (lto_symtab_get_identifier_decl): Remove. + (lto_symtab_set_identifier_decl): Likewise. + (lto_symtab_merge_decl): Rename to ... + (lto_symtab_merge): ... this. Rewrite. + (lto_symtab_merge_var): Remove. + (lto_symtab_merge_fn): Likewise. + (lto_symtab_prevailing_decl): Adjust. + (lto_cgraph_replace_node): New function. + (lto_symtab_merge_decls_2): Likewise. + (lto_symtab_merge_decls_1): Likewise. + (lto_symtab_fixup_var_decls): Likewise. + (lto_symtab_resolve_symbols): Likewise. + (lto_symtab_merge_decls): Likewise. + (lto_symtab_prevailing_decl): Adjust. + (lto_symtab_get_symtab_def): Remove. + (lto_symtab_get_file_data): Likewise. + (lto_symtab_clear_resolution): Adjust. + (lto_symtab_clear_resolution): Likewise. + * lto-cgraph.c (input_edge): Do not merge cgraph nodes here. + (input_cgraph_1): Likewise. + * lto-streamer-in.c (get_resolution): Do not provide fake + symbol resolutions here. + (deferred_global_decls): Remove. + (lto_register_deferred_decls_in_symtab): Likewise. + (lto_register_var_decl_in_symtab): Change signature, register + variable via lto_symtab_register_decl. + (lto_register_function_decl_in_symtab): Likewise. + (lto_read_tree): Adjust. + * lto-streamer.h (lto_register_deferred_decls_in_symtab): Remove. + (lto_symtab_merge_var): Likewise. + (lto_symtab_merge_fn): Likewise. + (lto_symtab_register_decl): Declare. + (lto_symtab_merge_decls): Likewise. + +2009-10-05 Richard Guenther + + PR tree-optimization/23821 + * tree-vrp.c (vrp_finalize): Do not perform copy propagation. + * tree-ssa-dom.c (cprop_operand): Do not propagate copies into + simple IV increments. + +2009-10-05 Ramana Radhakrishnan + + * config/arm/arm.c (arm_override_options): Really initialize + flag_dwarf2_cfi_asm to 0. + +2009-10-05 Doug Kwan + + PR rtl-optimization/41574 + * combine.c (distribute_and_simplify_rtx): Quit if RTX mode is + floating point and we are not doing unsafe math optimizations. + +2009-10-03 Simon Baldwin + Cary Coutant + Rafael Espindola + Richard Guenther + Jan Hubicka + Doug Kwan + H.J. Lu + Bill Maddox + Ryan Mansfield + Diego Novillo + Ollie Wild + Kenneth Zadeck + + * lto-cgraph.c: New file. + * lto-compress.c: New file. + * lto-compress.h: New file. + * lto-opts.c: New file. + * lto-section-in.c: New file. + * lto-section-out.c: New file. + * lto-streamer-in.c: New file. + * lto-streamer-out.c: New file. + * lto-streamer.c: New file. + * lto-streamer.h: New file. + * lto-symtab.c: New file. + * lto-wpa-fixup.c: New file. + * lto-wrapper.c: New file. + +2009-10-03 Simon Baldwin + Ben Elliston + Rafael Espindola + Nathan Froyd + Jan Hubicka + Doug Kwan + Diego Novillo + Kenneth Zadeck + + * Makefile.in (enable_lto): New. + (site.exp): If @enable_lto@ is set to 'yes' define ENABLE_LTO. + (LINKER_PLUGIN_API_H): Define. + (LTO_SYMTAB_H): Define. + (LTO_STREAMER_H): Define. + (TREE_VECTORIZER_H): Define. + (INCLUDES): Add LIBELFINC. + (OBJS-common): Add lto-cgraph.o, lto-streamer-in.o, + lto-streamer-out.o, lto-section-in.o, lto-section-out.o, lto-symtab.o, + lto-opts.o, lto-streamer.o, lto-wpa-fixup.o, lto-compress.o. + (MOSTLYCLEANFILES): Add lto-wrapper$(exeext) + (native): Add lto-wrapper$(exeext) + (lto-compress.o, lto-cgraph.o, lto-streamer-in.o, + lto-streamer-out.o, lto-section-in.o, lto-section-out.o, + lto-symtab.o, lto-opts.o, lto-streamer.o, lto-wpa-fixup.o): New rules. + (gimple.o): Add dependency on LTO_HEADER_H and LTO_SECTION_OUT_H. + (varasm.o): Add dependency on tree-iterator.h. + (cgraph.o): Add dependency on cif-code.def. + (ipa-reference.o): Add dependency on LTO_STREAMER_H. + (ipa-pure-const.o): Likewise. + (GTFILES): Add lto-symtab.c. + (install-lto-wrapper): New. + * configure.ac: If 'lto' is in enable_languages, define ENABLE_LTO + and enable_lto. If LIBELFLIBS is set, define HAVE_libelf. + * config.in: Regenerate. + +2009-10-03 Rafael Espindola + Diego Novillo + + * cgraphunit.c (ipa_passes): Prevent lto1 from calling + ipa_write_summaries. + Call execute_ipa_summary_passes for all_regular_ipa_passes and + all_lto_gen_passes. + (cgraph_optimize): Make extern. + +2009-10-03 Nathan Froyd + Kenneth Zadeck + + * toplev.c (in_lto_p): Declare. + * collect2.c (scan_prog_file): Read all the output when reading + information for LTO. + (enum lto_mode_d): Declare. + +2009-10-03 Richard Guenther + Diego Novillo + + * gimple.c: Include target.h and alias.h. + (gimple_types): Declare. + (type_hash_cache): Declare. + (gimple_alloc_stat): Make extern. + (gimple_build_eh_must_not_throw): Call + gimple_eh_must_not_throw_set_fndecl. + (struct type_pair_d): Declare. + (type_pair_t): Declare. + (type_pair_hash): New. + (type_pair_eq): New. + (lookup_type_pair): New. + (gimple_force_type_merge): New. + (compare_type_names_p): New. + (compare_field_offset): New. + (gimple_types_compatible_p): New. + (struct sccs): Declare. + (next_dfs_num): Declare. + (iterative_hash_gimple_type): New. + (visit): New. + (iterative_hash_type_name): New. + (iterative_hash_gimple_type): New. + (gimple_type_hash): New. + (gimple_type_eq): New. + (gimple_register_type): New. + (print_gimple_types_stats): New. + (gimple_signed_or_unsigned_type): New. + (gimple_unsigned_type): New. + (gimple_signed_type): New. + (gimple_get_alias_set): New. + (gimple_decl_printable_name): Do not use DMGL_TYPES. + * gimple.h (gimple_alloc, gimple_alloc_stat): Declare. + (gimple_force_type_merge): Declare. + (gimple_types_compatible_p): Declare. + (gimple_register_type): Declare. + (print_gimple_types_stats): Declare. + (gimple_unsigned_type): Declare. + (gimple_signed_type): Declare. + (gimple_get_alias_set): Declare. + (gimple_eh_must_not_throw_set_fndecl): New. + +2009-10-03 Jan Hubicka + Kenneth Zadeck + + * ipa-pure-const.c: Include lto-streamer.h. + (register_hooks): Factor out of ... + (generate_summary): ... here. + (pure_const_write_summary): New. + (pure_const_read_summary): New. + (pass_ipa_pure_const): Add pure_const_write_summary and + pure_const_read_summary. + * ipa-reference.c: Include lto-streamer.h. + (add_new_function): New. + (remove_node_data): New. + (duplicate_node_data): New. + (ipa_init): Guard against multiple calls. + Move hook setup from analyze_function. + (write_node_summary_p): New. + (ipa_reference_write_summary): New. + (ipa_reference_read_summary): New. + (pass_ipa_reference): Add ipa_reference_write_summary and + ipa_reference_read_summary. + * cgraph.h (cgraph_local_info): Add field lto_file_data. + (struct cgraph_edge): Add fields lto_stmt_uid and + call_stmt_cannot_inline_p. + (cgraph_optimize): Declare. + (cgraph_decide_is_function_needed): Declare. + (reset_inline_failed): Declare. + (enum LTO_cgraph_tags): Declare. + (LTO_cgraph_tag_names): Declare. + (LCC_NOT_FOUND): Define. + +2009-10-03 Doug Kwan + Rafael Espindola + Jan Hubicka + Diego Novillo + Kenneth Zadeck + + * passes.c (all_regular_ipa_passes): New. + (all_ipa_passes): Rename to all_small_ipa_passes. + (init_optimization_passes): Init all_regular_ipa_passes. + * tree-pass.h (all_regular_ipa_passes): New. + (all_ipa_passes): Rename to all_small_ipa_passes. + * passes.c (all_lto_gen_passes): New. + (init_optimization_passes): Initialize all_lto_gen_passes. + (execute_ipa_summary_passes): Make non-static. + (ipa_write_summaries_1): New. + (ipa_write_summaries_2): New. + (ipa_write_summaries): New. + (ipa_write_summaries_of_cgraph_node_set): New. + (ipa_read_summaries_1): New. + (ipa_read_summaries): New. + (execute_ipa_pass_list): Call cgraph_process_new_functions. + (execute_regular_ipa_pass_list): Remove. + (init_optimization_passes): Schedule + pass_rebuild_cgraph_edges and pass_early_inline outside + of pass_all_early_optimizations. Document reason. + (pass_ipa_lto_gimple_out, pass_ipa_lto_wpa_fixup, + pass_ipa_lto_finish_out): New pass. + (pass_ipa_summary_passes): Start and stop timers if the pass has them. + (execute_all_ipa_transforms): New. + (execute_one_pass): Don't call execute_one_ipa_transform_pass. + (dump_properties, debug_properties): New. + * tree-optimize.c (gate_all_early_local_passes): Return + false if we are in lto1. + (tree_rest_of_compilation): Call execute_all_ipa_transforms. + * tree-pass.h (execute_all_ipa_transforms): Declare. + (pass_ipa_function_and_variable_visibility): Declare. + (pass_ipa_early_inline): Declare. + (pass_ipa_lto_gimple_out): Declare. + (pass_ipa_lto_wpa_fixup): Declare. + (pass_ipa_lto_finish_out): Declare. + (all_small_ipa_passes, all_regular_ipa_passes, + all_lto_gen_passes): Declare. + (execute_ipa_summary_passes): Declare. + (execute_all_ipa_transforms): Declare. + (ipa_write_summaries): Declare + (ipa_write_summaries_of_cgraph_node_set): Declare. + (ipa_read_summaries): Declare. + +2009-10-03 Doug Kwan + Ollie Wild + + * ipa-prop.c (ipa_propagate_indirect_call_infos): Do nothing in WPA. + + * collect2.c (LTO_MODE_NONE, LTO_MODE_LTO, LTO_MODE_WPA): New enums. + (lto_mode): New variable. + (maybe_run_lto_and_relink): Handle the -fwpa option. + (main): Handle the -fwpa option. + (maybe_unlink_list): New function. + * gcc.c (link_lto_options): Replace -flto with -fwpa. + * common.opt (flto): New flag. + * toplev.c (flag_generate_lto): Declare. + +2009-10-03 Simon Baldwin + + * common.opt (flto-compression-level): New flag. + + * opts.c: Include lto-opts.h. + (handle_option): Call lto_register_user_option for each + valid option handled. + (decode_options): Clear registered options before the options + handling loop. + +2009-10-03 Cary Coutant + + * collect2.c (is_elf): New function. + (scan_prog_file): Require LTO object to be in ELF format. + +2009-10-03 Rafael Espindola + + * gcc.c (LINK_COMMAND_SPEC): Use the -pass-through option to pass + libgcc to the linker. + + * ipa-cp.c (cgraph_gate_cp): Return false if LTRANS is running. + + * collect2.c (maybe_run_lto_and_relink): Execute lto-wrapper. + (collect_execute): Add flags argument. Pass flags to pex_run. Update + all callers. + * collect2.h (collect_execute): Add flags argument. + * tlink.c (tlink_execute): Update call to collect_execute. + * gcc.c (main): Set the COLLECT_LTO_WRAPPER environment variable. + (use_linker_plugin): New. + (use_linker_plugin_spec_function): New. + (LINK_COMMAND_SPEC): Pass plugin options to the linker. + (linker_plugin_file_spec): New. + (lto_wrapper_spec): New. + (lto_gcc_spec): New. + (static_specs): Add linker_plugin_file, lto_wrapper and lto_gcc. + (static_spec_functions): Add use-linker-plugin. + (process_command): Handle -use-linker-plugin. + (main): Use lto_wrapper_spec instead of lto_wrapper. Set + linker_plugin_file_spec and lto_gcc_spec. + (use_linker_plugin_spec_function): New. + +2009-10-03 Richard Guenther + + PR lto/41547 + PR lto/41548 + * tree.h (is_lang_specific): Include LANG_TYPE. + * tree.c (find_decls_types_r): Manually add interesting parts + of TYPE_FIELDS. Walk BINFO_VIRTUALS. Do not walk TYPE_METHODS. + + * gimple.c (type_pair_hash): Make symmetric. + (type_pair_eq): Likewise. + (lookup_type_pair): Increase initial hashtable size. + (gimple_force_type_merge): Rely on type-pair symmetry. + (visit): Remove excessive checking code. + (iterative_hash_type_name): Do not hash TYPE_NAME of anonymous unions. + (gimple_register_type): Remove getenv calls, shrink initial + hashtable size. + + PR middle-end/41502 + * cgraphunit.c (ipa_passes): Do not remove bodies of extern + inline functions if not generating lto output. + + PR lto/41379 + * toplev.c (finalize): In WPA mode remove the asm file. + +2009-10-03 Doug Kwan + + * ipa-inline.c (cgraph_mark_inline): Check + edge->call_stmt_cannot_inline_p instead of calling + gimple_call_cannot_inline_p. + (cgraph_decide_inlining): Do nothing in WPA and LTRANS. + (cgraph_gate_ipa_early_inlining): Return false if in_lto_p is set. + (inline_generate_summary): Do nothing in LTRANS. + * cgraph.c (initialize_inline_failed): Make sure e->call_stmt + exists before calling gimple_call_cannot_inline_p. + (cgraph_create_edge): Set edge->call_stmt_cannot_inline_p. + (cgraph_clone_edge): Add argument STMT_UID. Modify all callers. + Update new_edge->lto_stmt_uid. + * cgraphbuild.c (reset_inline_failed): New. + + * common.opt (fwpa): New flag. + (fltrans): New option. + * gcc.c (gcc_lto_option_t): New type. + (current_lto_option): New variable. + (lto_single_spec_function): Remove and is replaced by .. + (lto_option_spec_function): New function. + (LINK_COMMAND_SPEC): Use link_lto_option spec instead of just + passing the -flto flag. + (cc1_options): Separate non-LTO related parts into .. + (cc1_non_lto_options): Non-LTO related options shared by all FEs. + (lto1_options): New spec for lto FE. + (link_lto_options): New spec for handling LTO flags in linker. + (invoke_lto_single): Re-format to fit in 80 column. Replace + lto-single with lto-option. + (static_specs): Add cc1_non_lto_options, lto1_options and + link_lto_options. + (static_spec_function): Replace lto-single with lto-option. + (process_command): Handle -flto, -fwpa and -fltran by setting + current_lto_option and not passing it to subprocess unconditionally. + +2009-10-03 Bill Maddox + + Add `gcc' driver support for link-time code generation (LTO). + + * collect2.c (enum pass): Add new literal PASS_LTOINFO. + (lto_flag, lto_objects, lto_o_file): New variables. + (struct lto_object, struct lto_object_list): New structures. + (collect_exit, handler): Remove LTO temporary output file on exit. + (add_lto_object): New function. + (maybe_run_lto_and_relink): New function. Perform link time code + generation and relinking for object files containing LTO information. + (main): Invoke maybe_run_lto_and_relink(). + (dump_argv): New function. For debugging, currently disabled. + (scan_prog_file): Add LTO information pass. + * gcc.c (LINK_COMMAND_SPEC): Pass `-flto' switch to linker, i.e., + collect2. + * toplev.c (compile_file): Emit assembler directive to create + the `gnu_lto_v1' marker symbol when compiling with `-flto'. + +2009-10-03 Diego Novillo + + * c.opt: Add LTO to warn_abi and warn_psabi. + + * tree.c (fld_worklist_push): Rename from PUSH. Convert to static + inline function. Ignore language-specific nodes. Update all users. + (find_decls_types_r): Do not traverse the subtrees of + language-specific nodes. Do not traverse DECL_INITIAL for TYPE_DECLs. + * tree.h (is_lang_specific): New. + * langhooks.h (struct lang_hooks_for_decls): Remove + may_need_assembler_name_p. Update all users. + + * c-common.c (set_builtin_user_assembler_name): Move ... + * builtins.c (set_builtin_user_assembler_name): ... here. + (is_builtin_name): Add comment + (is_builtin_fn): New. + * except.c (output_ttype): Only call + lookup_type_for_runtime if TYPE is not a runtime type. + + * passes.c (register_pass): Call position_pass on + all_small_ipa_passes, all_regular_ipa_passes and all_lto_gen_passes. + * timevar.def (TV_IPA_LTO_GIMPLE_IO): Define. + (TV_IPA_LTO_DECL_IO): Define. + (TV_IPA_LTO_CGRAPH_IO): Define. + (TV_LTO): Define. + (TV_WHOPR_WPA): Define. + (TV_WHOPR_WPA_IO): Define. + (TV_WHOPR_LTRANS): Define. + (TV_WHOPR_WPA_FIXUP): Define. + (TV_WHOPR_WPA_LTRANS_EXEC): Define. + * tree-cfg.c (tree_node_can_be_shared): Make extern. + * tree-flow.h (tree_node_can_be_shared): Declare. + * tree-inline.c (tree_can_inline_p): Check that E has a + statement associated with it. + * tree.c (free_lang_data_in_binf): Factor out of ... + (free_lang_data_in_type): ... here. + Call RECORD_OR_UNION_TYPE_P. + (need_assembler_name_p): Ignore DECL if it does not have TREE_PUBLIC + set. Call lang_hooks.decls.may_need_assembler_name_p if set. + (free_lang_data_in_decl): Do not clear DECL_CONTEXT for CONST_DECLs. + (free_lang_data): Set debug_info_level to DINFO_LEVEL_NONE. Set + write_symbols to NO_DEBUG. Set debug_hooks to do_nothing_debug_hooks. + (gate_free_lang_data): Return true if flag_generate_lto is set. + (walk_tree_1): Call RECORD_OR_UNION_TYPE_P. + * c-common.h (set_builtin_user_assembler_name): Move ... + * tree.h (set_builtin_user_assembler_name): ... here. + + * common.opt (flto-report): New flag. + * opts.c (complain_wrong_lang): Do not complain if running lto1. + * collect2.c (scan_prog_file): Send the error output of + 'nm' to HOST_BIT_BUCKET. + +2009-10-03 Ollie Wild + + * langhooks-def.h (lhd_begin_section): New function declaration. + (lhd_write_section): New function declaration. + (lhd_end_section): New function declaration. + (LANG_HOOKS_BEGIN_SECTION): New macro. + (LANG_HOOKS_WRITE_SECTION_DATA): New macro. + (LANG_HOOKS_END_SECTION): New macro. + (LANG_HOOKS_LTO): New macro. + (LANG_HOOKS_INITIALIZER): Add LANG_HOOKS_LTO. + * langhooks.c (output.h): Add include. + (saved_section): New static variable. + (lhd_begin_section): New function. + (lhd_write_section_data): New function. + (lhd_end_section): New function. + * langhooks.h (struct lang_hooks_for_lto): New structure. + (struct lang_hooks): Add member lto. + * Makefile.in (langhooks.o): Add dependency on output.h. + + * c-opts.c (c_common_post_options): Handle -flto and -fwhopr. + +2009-10-03 Richard Guenther + + * config/rs6000/rs6000.c (rs6000_output_function_epilogue): + Handle LTO. + +2009-10-03 Simon Baldwin + Richard Guenther + Janis Johnson + Doug Kwan + Diego Novillo + Ramana Radhakrishnan + Ollie Wild + + * doc/install.texi: Add documentation for libelf and --enable-lto. + * doc/invoke.texi: Document -fwpa, -flto, -fwhopr, -fltrans, + -flto-report, -flto-compression-level and -use-linker-plugin. + * doc/sourcebuild.texi: Document use of zlib. Document lto-plugin. + Add section for LTO Testing. + 2009-10-02 Cary Coutant - Add support for comdat type sections for DWARF v4. Merge from dwarf4 - branch. + Add support for comdat type sections for DWARF v4. + Merge from dwarf4 branch. + * dwarf2out.c (DWARF_TYPE_SIGNATURE_SIZE): New constant. (dw_die_ref): Define vector type. (enum dw_val_class): Add dw_val_class_data8. @@ -21,8 +3907,7 @@ (print_signature): New function. (print_die): Print signature information; add dw_val_class_data8. (attr_checksum): Support dw_val_class_data8. - (CHECKSUM_STRING): Redefine for DWARF-4 to include - trailing NULL byte. + (CHECKSUM_STRING): Redefine for DWARF-4 to include trailing NULL byte. (CHECKSUM_SLEB128, CHECKSUM_ULEB128): New macros. (checksum_sleb128, checksum_uleb128): New functions. (checksum_die_context): New function. @@ -54,7 +3939,7 @@ (copy_decls_for_unworthy_types): New function. (build_abbrev_table): Don't assert on missing die_symbol when doing comdat type sections. - (size_of_die): Use DW_FORM_sig8 for external references; Add + (size_of_die): Use DW_FORM_sig8 for external references. Add dw_val_class_data8. (unmark_dies): Don't assert for unmarked dies when doing comdat type sections. @@ -85,27 +3970,28 @@ 2009-10-02 Neil Vachharajani - * gcov-io.c (gcov_open): Open files read-only when MODE < 0 + * gcov-io.c (gcov_open): Open files read-only when MODE < 0. 2009-10-02 Uros Bizjak - * config/i386/i386.md (divmod4) Macroize expander from - divmoddi4, divmodsi4 and divmodhi4 patterns using SWI248 macro. + * config/i386/i386.md (SWIM248): New mode iterator. + (divmod4) Macroize expander from divmoddi4, divmodsi4 and + divmodhi4 patterns using SWIM248 macro. (*divmod4): Macroize insn_and_split pattern from *divmoddi4_cltd_rex64, *divmodsi4_cltd and divmodhi4 insn patterns - and their corresponding splitters usign SWI248 macro. Split SImode + and their corresponding splitters usign SWIM248 macro. Split SImode insn to generate cltd and DImode insn to generate cqto instead of move+shift when optimizing for size or TARGET_USE_CLTD is in effect. (*divmoddi4_nocltd_rex64, *divmodsi4_nocltd): Remove insn patterns. (*divmod4_noext): Macroize insn from *divmoddi_noext_rex64 and - *divmodsi_noext patterns using SWI248 macro. + *divmodsi_noext patterns using SWIM248 macro. (udivmod4): Macroize expander from udivmoddi4, udivmodsi4 and - udivmodhi4 patterns using SWI248 macro. + udivmodhi4 patterns using SWIM248 macro. (*udivmod4): Macroize insn_and_split pattern from *udivmoddi4, udivmodsi4 and udivmodhi4 patterns and their - corresponding splitters using SWI248 macro. + corresponding splitters using SWIM248 macro. (*udivmod4_noext): Macroize insn from *udivmoddi4_noext, - *udivmodsi4_noext and *udivmodhi_noext patterns using SWI248 macro. + *udivmodsi4_noext and *udivmodhi_noext patterns using SWIM248 macro. 2009-10-02 Eric Botcazou @@ -127,8 +4013,8 @@ PR debug/41404 PR debug/41353 * cfgexpand.c (expand_debug_expr) : Don't create - CONST_STRING if STRING_CST contains embedded '\0's or doesn't end with - '\0'. + CONST_STRING if STRING_CST contains embedded '\0's or doesn't end + with '\0'. (expand_debug_expr) : For TREE_STATIC !DECL_EXTERNAL vars use DECL_RTL with resetting it back to NULL afterwards. * dwarf2out.c (same_dw_val_p): For dw_val_class_addr compare with @@ -394,7 +4280,7 @@ pressure. 2009-09-29 Basile Starynkevitch - Rafael Avila de Espindola + Rafael Avila de Espindola * gengtype.c (plugin_output): New. (get_output_file_with_visibility): Return plugin_output for plugins. @@ -419,7 +4305,7 @@ (x86_64-*-*): Ditto. * config/i386/smmintrin.h: Move instructions in mmintrin-common.h back to smmintrin.h. - * config/i386/cpuid.h: (bit_SSE5): Remove SSE5 bit. + * config/i386/cpuid.h (bit_SSE5): Remove SSE5 bit. * config/i386/x86intrin.h: Remove SSE5. * config/i386/mmintrin-common.h: Delete file. * doc/extend.texi (x86 intrinsics): Remove SSE5 flags and builtins. @@ -548,8 +4434,7 @@ 2009-09-28 Nick Clifton - * config/m32r/m32r.c (m32r_is_insn): Return false for debugging - insns. + * config/m32r/m32r.c (m32r_is_insn): Return false for debugging insns. 2009-09-28 Duncan Sands @@ -618,7 +4503,7 @@ 2009-09-27 Peter O'Gorman - collect2.c (main): Look for -brtl before adding libraries. + * collect2.c (main): Look for -brtl before adding libraries. 2009-09-27 Jonathan Gray @@ -698,9 +4583,10 @@ * dwarf2out.c (dwarf_tag_name, gen_generic_params_dies, generic_parameter_die, template_parameter_pack_die, - gen_formal_parameter_die, gen_subprogram_die): Adjust after renaming - DW_TAG_formal_parameter_pack and DW_TAG_template_parameter_pack into - DW_TAG_GNU_formal_parameter_pack and DW_TAG_GNU_template_parameter_pack. + gen_formal_parameter_die, gen_subprogram_die): Adjust after + renaming DW_TAG_formal_parameter_pack and + DW_TAG_template_parameter_pack into DW_TAG_GNU_formal_parameter_pack + and DW_TAG_GNU_template_parameter_pack. 2009-09-25 Anatoly Sokolov @@ -748,9 +4634,7 @@ (reg_class): Likewise. (REG_CLASS_NAMES): Likewise. * config/m32c/m32c.c (m32c_reg_class_from_constraint): Likewise. - - * config/m32c/m32c.c (m32c_override_options): Disable -fivopts for - M32C. + (m32c_override_options): Disable -fivopts for M32C. 2009-09-24 Michael Meissner @@ -871,7 +4755,8 @@ * config/xtensa/xtensa.c (TARGET_STATIC_CHAIN): New. (xtensa_static_chain): New. - * config/xtensa/xtensa.h (STATIC_CHAIN, STATIC_CHAIN_INCOMING): Remove. + * config/xtensa/xtensa.h (STATIC_CHAIN): Remove. + (STATIC_CHAIN_INCOMING): Remove. 2009-09-23 Anatoly Sokolov @@ -6488,7 +10373,7 @@ (function_value): Adjust for above modification. (alpha_va_start) : Use virtual_incoming_args_rtx as base object, not next_arg. - * config/alpha/vms.h: (DEFAULT_PCC_STRUCT_RETURN): Define as 0. + * config/alpha/vms.h (DEFAULT_PCC_STRUCT_RETURN): Define as 0. 2009-08-11 Ulrich Weigand @@ -6581,7 +10466,7 @@ * config/alpha/vms.h (ASM_OUTPUT_EXTERNAL): Define. (DO_CRTL_NAMES): Define. (LIB_SPEC): Remove. - * config/alpha/vms64.h: (POINTERS_EXTEND_UNSIGNED): Remove undef. + * config/alpha/vms64.h (POINTERS_EXTEND_UNSIGNED): Remove undef. (LONG_TYPE_SIZE): Define. (TARGET_OS_CPP_BUILTINS): Define with __LONG_POINTERS=1 (SUBTARGET_SWITCHES): Define malloc64 switch. @@ -6974,11 +10859,6 @@ * calls.c (emit_library_call_value_1): Update call to hard_libcall_value. * explow.c (hard_libcall_value): Use new target hook. - * testsuite/lib/target-supports.exp - (check_effective_target_arm_hard_vfp_ok): New hook. - (check_effective_target_arm_neon_ok): Improve test for neon - availability. - * testsuite/gcc.target/arm/eabi1.c: Only run test in base variant. * config/arm/arm.c: Include cgraph.h (TARGET_FUNCTION_VALUE): Override default hook. (arm_pcs_default): New variable. @@ -8473,7 +12353,7 @@ combined_args_to_skip and args_to_skip. * tree-inline.c (update_clone_info): New function. (tree_function_versioning): Call update_clone_info. - * cgraphunit.c: (cgraph_materialize_clone): Dump materialized + * cgraphunit.c (cgraph_materialize_clone): Dump materialized functions. (cgraph_materialize_all_clones): More extensive dumping, working with combined_args_to_skip rather than args_to_skip. @@ -8803,7 +12683,7 @@ * doc/sourcebuild.texi: Document install-plugin target. * configure.ac: Added install-plugin target to language makefiles. * configure: Regenerate. - * Makefile.in: (install-plugin): Install more headers, + * Makefile.in (install-plugin): Install more headers, depend on lang.install-plugin. 2009-07-15 Manuel López-Ibáñez @@ -9132,7 +13012,7 @@ 2009-07-08 DJ Delorie - * config/mep/mep.c: (mep_option_can_inline_p): New. + * config/mep/mep.c (mep_option_can_inline_p): New. (TARGET_OPTION_CAN_INLINE_P): Define. 2009-07-08 Mark Wielaard @@ -11356,10 +15236,10 @@ (LARGEST_EXPONENT_IS_NORMAL): Define. * config/arm/arm-protos.h (arm_emit_fp16_const): Declare. * config/arm/arm-modes.def (HFmode): Define. - * config/arm/vfp.md: (*movhf_vfp): New. + * config/arm/vfp.md (*movhf_vfp): New. (extendhfsf2): New. (truncsfhf2): New. - * config/arm/arm.md: (fpu): Add neon_fp16. + * config/arm/arm.md (fpu): Add neon_fp16. (floatsihf2, floatdihf2): New. (fix_trunchfsi2, fix_trunchfdi2): New. (truncdfhf2): New. @@ -12073,7 +15953,7 @@ (c_parser_expr_list): Same. (c_parser_omp_atomic): Same. (c_parser_omp_for_loop): Same. - * c-tree.h: (struct c_declarator): Add comment to id_loc. + * c-tree.h (struct c_declarator): Add comment to id_loc. (build_array_declarator): New argument. * c-decl.c (build_array_declarator): Add location argument. (grokdeclarator): Set id_loc for cdk_array. @@ -12084,7 +15964,6 @@ (OMP_CLAUSE_LOCATION): New macro. (struct tree_omp_clause): Add location field. (build_omp_clause): Add argument. - * testsuite/gcc.dg/gomp/for-1.c: Fix column. * cp/pt.c (tsubst_omp_for_iterator): Pass location to build_omp_clause. * cp/parser.c (cp_parser_omp_var_list_no_open): Same. @@ -14789,7 +18668,7 @@ * hooks.h (hook_tree_const_tree_null): Declare. * target.h (struct gcc_target): Add invalid_parameter_type, invalid_return_type, promoted_type, and convert_to_type fields. - * target-def.h: (TARGET_INVALID_PARAMETER_TYPE): Define. + * target-def.h (TARGET_INVALID_PARAMETER_TYPE): Define. (TARGET_INVALID_RETURN_TYPE): Define. (TARGET_PROMOTED_TYPE): Define. (TARGET_CONVERT_TO_TYPE): Define. @@ -17206,7 +21085,7 @@ 2009-05-04 Michael Eager - * gcc/config.gcc: (powerpc-xilinx-eabi*): Add tm t-xilinx + * gcc/config.gcc (powerpc-xilinx-eabi*): Add tm t-xilinx * config/rs6000/t-xilinx: New 2009-05-04 Paolo Bonzini @@ -18234,7 +22113,7 @@ * ssaexpand.h (struct ssaexpand): Member 'values' is a bitmap. (get_gimple_for_ssa_name): Adjust, lookup using SSA_NAME_DEF_STMT. - * tree-ssa-live.h: (find_replaceable_exprs): Return a bitmap. + * tree-ssa-live.h (find_replaceable_exprs): Return a bitmap. (dump_replaceable_exprs): Take a bitmap. * cfgexpand.c (gimple_cond_pred_to_tree): Handle bitmap instead of array. @@ -19238,7 +23117,7 @@ * cfghooks.c (tidy_fallthru_edges): Remove find_basic_blocks references from comments. - * cfgbuild.c: (count_basic_blocks): Delete. + * cfgbuild.c (count_basic_blocks): Delete. (find_basic_blocks_1): Delete. (find_basic_blocks): Delete. * except.c (finish_eh_generation): Make static. Move comment from @@ -22477,7 +26356,7 @@ * config/vax/builtins.md (jbbssiqi, jbbssihi, jbbssisi, jbbcciqi, jbbccihi, jbbccisi): Remova trailing whitespace. * config/vax/constraints.md: Likewise. - * config/vax/elf.h: (ASM_PREFERRED_EH_DATA_FORMAT): Likewise. + * config/vax/elf.h (ASM_PREFERRED_EH_DATA_FORMAT): Likewise. * config/vax/openbsd1.h (OBSD_OLD_GAS): Likewise. * config/vax/predicates.md: Likewise. * config/vax/vax.c (print_operand_address, vax_output_int_move, diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP index c090cdcd4e2..459615d7a95 100644 --- a/gcc/DATESTAMP +++ b/gcc/DATESTAMP @@ -1 +1 @@ -20091002 +20091106 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 40fe3ba80fd..f66f9ef0bf4 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -309,6 +309,13 @@ PPLINC = @PPLINC@ CLOOGLIBS = @CLOOGLIBS@ CLOOGINC = @CLOOGINC@ +# How to find libelf +LIBELFLIBS = @LIBELFLIBS@ +LIBELFINC = @LIBELFINC@ + +# Set to 'yes' if the LTO front end is enabled. +enable_lto = @enable_lto@ + # Libs and linker option needed for plugin support PLUGINLIBS = @pluginlibs@ @@ -407,6 +414,10 @@ PARTITION_H = $(srcdir)/../include/partition.h MD5_H = $(srcdir)/../include/md5.h DWARF2_H = $(srcdir)/../include/dwarf2.h +# Linker plugin API headers +LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h +LTO_SYMTAB_H = $(srcdir)/../include/lto-symtab.h + # Default native SYSTEM_HEADER_DIR, to be overridden by targets. NATIVE_SYSTEM_HEADER_DIR = /usr/include # Default cross SYSTEM_HEADER_DIR, to be overridden by targets. @@ -917,6 +928,9 @@ REAL_H = real.h $(MACHMODE_H) IRA_INT_H = ira.h ira-int.h $(CFGLOOP_H) alloc-pool.h DBGCNT_H = dbgcnt.h dbgcnt.def EBITMAP_H = ebitmap.h sbitmap.h +LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \ + $(CGRAPH_H) vec.h vecprim.h $(TREE_H) $(GIMPLE_H) +TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H) IPA_PROP_H = ipa-prop.h $(TREE_H) vec.h $(CGRAPH_H) GSTAB_H = gstab.h stab.def BITMAP_H = bitmap.h $(HASHTAB_H) statistics.h @@ -976,7 +990,8 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY) # and the system's installed libraries. LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) \ $(HOST_LIBS) -BACKENDLIBS = $(CLOOGLIBS) $(PPLLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) +BACKENDLIBS = $(CLOOGLIBS) $(PPLLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) \ + $(ZLIB) $(LIBELFLIBS) # Any system libraries needed just for GNAT. SYSLIBS = @GNAT_LIBEXC@ @@ -1005,7 +1020,7 @@ BUILD_ERRORS = build/errors.o INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \ -I$(srcdir)/../include @INCINTL@ \ $(CPPINC) $(GMPINC) $(DECNUMINC) \ - $(PPLINC) $(CLOOGINC) + $(PPLINC) $(CLOOGINC) $(LIBELFINC) .c.o: $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION) @@ -1215,6 +1230,16 @@ OBJS-common = \ loop-unroll.o \ loop-unswitch.o \ lower-subreg.o \ + lto-cgraph.o \ + lto-streamer-in.o \ + lto-streamer-out.o \ + lto-section-in.o \ + lto-section-out.o \ + lto-symtab.o \ + lto-opts.o \ + lto-streamer.o \ + lto-wpa-fixup.o \ + lto-compress.o \ mcf.o \ mode-switching.o \ modulo-sched.o \ @@ -1411,7 +1436,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-config.h insn-codes.h \ genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \ xgcc$(exeext) cpp$(exeext) cc1$(exeext) cc1*-dummy$(exeext) $(EXTRA_PASSES) \ $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \ - $(SPECS) collect2$(exeext) \ + $(SPECS) collect2$(exeext) lto-wrapper$(exeext) \ gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \ *.[0-9][0-9].* *.[si] *-checksum.c libbackend.a libgcc.mk @@ -1692,7 +1717,7 @@ rest.encap: lang.rest.encap # This is what is made with the host's compiler # whether making a cross compiler or not. native: config.status auto-host.h build-@POSUB@ $(LANGUAGES) \ - $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2) + $(EXTRA_PASSES) $(EXTRA_PROGRAMS) $(COLLECT2) lto-wrapper$(exeext) # Define the names for selecting languages in LANGUAGES. c: cc1$(exeext) @@ -1957,7 +1982,7 @@ c-convert.o : c-convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ c-pragma.o: c-pragma.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(FUNCTION_H) $(C_PRAGMA_H) $(TOPLEV_H) output.h $(GGC_H) $(TM_P_H) \ $(C_COMMON_H) $(TARGET_H) gt-c-pragma.h $(CPPLIB_H) $(FLAGS_H) $(DIAGNOSTIC_H) \ - opts.h + opts.h $(PLUGINS_H) graph.o: graph.c $(SYSTEM_H) coretypes.h $(TM_H) $(TOPLEV_H) $(FLAGS_H) output.h \ $(RTL_H) $(FUNCTION_H) hard-reg-set.h $(BASIC_BLOCK_H) graph.h $(OBSTACK_H) \ $(CONFIG_H) @@ -1987,6 +2012,12 @@ collect2-aix.o : collect2-aix.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ tlink.o: tlink.c $(DEMANGLE_H) $(HASHTAB_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(OBSTACK_H) collect2.h intl.h +lto-wrapper$(exeext): lto-wrapper.o intl.o $(LIBDEPS) + $(COMPILER) $(ALL_COMPILERFLAGS) $(LDFLAGS) -o T$@ lto-wrapper.o intl.o $(LIBS) + mv -f T$@ $@ + +lto-wrapper.o: lto-wrapper.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) intl.h + # A file used by all variants of C. c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ @@ -2158,17 +2189,61 @@ convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) +# lto-compress.o needs $(ZLIBINC) added to the include flags. +lto-compress.o: lto-compress.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TREE_H) langhooks.h $(LTO_HEADER_H) $(LTO_SECTION_H) \ + lto-compress.h $(DIAGNOSTIC_H) errors.h + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(ZLIBINC) $< $(OUTPUT_OPTION) + +lto-cgraph.o: lto-cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TOPLEV_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \ + $(VARRAY_H) $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) \ + $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) \ + except.h $(TIMEVAR_H) output.h pointer-set.h $(LTO_STREAMER_H) +lto-streamer-in.o: lto-streamer-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TOPLEV_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h $(VARRAY_H) \ + $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) \ + $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) libfuncs.h $(EXCEPT_H) debug.h \ + $(TIMEVAR_H) output.h $(IPA_UTILS_H) $(LTO_STREAMER_H) +lto-streamer-out.o : lto-streamer-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \ + $(VARRAY_H) $(HASHTAB_H) $(BASIC_BLOCK_H) tree-iterator.h \ + $(TREE_FLOW_H) $(TREE_PASS_H) $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) \ + $(DIAGNOSTIC_H) except.h $(LTO_STREAMER_H) errors.h +lto-section-in.o: lto-section-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + $(TOPLEV_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h $(VARRAY_H) \ + $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(CGRAPH_H) $(FUNCTION_H) \ + $(GGC_H) $(DIAGNOSTIC_H) except.h $(TIMEVAR_H) output.h \ + $(LTO_STREAMER_H) lto-compress.h +lto-section-out.o : lto-section-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(PARAMS_H) input.h \ + $(VARRAY_H) $(HASHTAB_H) $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(TREE_PASS_H) \ + $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) except.h pointer-set.h \ + $(BITMAP_H) langhooks.h $(LTO_STREAMER_H) lto-compress.h +lto-symtab.o: lto-symtab.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + toplev.h $(TREE_H) $(GIMPLE_H) $(GGC_H) $(LAMBDA_H) $(HASHTAB_H) \ + $(LTO_STREAMER_H) $(LINKER_PLUGIN_API_H) gt-lto-symtab.h +lto-opts.o: lto-opts.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ + $(HASHTAB_H) $(GGC_H) $(BITMAP_H) $(FLAGS_H) opts.h options.h \ + $(TARGET_H) $(TOPLEV_H) $(LTO_STREAMER_H) +lto-streamer.o: lto-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TREE_H) $(GIMPLE_H) $(BITMAP_H) $(LTO_STREAMER_H) $(FLAGS_H) \ + $(TREE_FLOW_H) $(DIAGNOSTIC_H) $(LTO_SYMTAB_H) $(TOPLEV_H) +lto-wpa-fixup.o: lto-wpa-fixup.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ + $(TM_H) $(TOPLEV_H) $(TREE_H) $(EXPR_H) $(FLAGS_H) $(CGRAPH_H) \ + $(FUNCTION_H) $(DIAGNOSTIC_H) $(BITMAP_H) $(TIMEVAR_H) \ + $(TREE_FLOW_H) $(TREE_PASS_H) $(LTO_STREAMER_H) langhooks.o : langhooks.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(TOPLEV_H) $(TREE_INLINE_H) $(RTL_H) insn-config.h $(INTEGRATE_H) \ langhooks.h $(TARGET_H) $(LANGHOOKS_DEF_H) $(FLAGS_H) $(GGC_H) $(DIAGNOSTIC_H) \ - intl.h $(GIMPLE_H) $(CGRAPH_H) + intl.h $(GIMPLE_H) $(CGRAPH_H) output.h tree.o : tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ all-tree.def $(FLAGS_H) $(FUNCTION_H) $(PARAMS_H) \ $(TOPLEV_H) $(GGC_H) $(HASHTAB_H) $(TARGET_H) output.h $(TM_P_H) \ langhooks.h $(REAL_H) gt-tree.h $(TREE_INLINE_H) tree-iterator.h \ $(BASIC_BLOCK_H) $(TREE_FLOW_H) $(OBSTACK_H) pointer-set.h fixed-value.h \ tree-pass.h $(LANGHOOKS_DEF_H) $(DIAGNOSTIC_H) $(CGRAPH_H) $(TIMEVAR_H) \ - $(EXCEPT_H) debug.h + $(EXCEPT_H) debug.h intl.h tree-dump.o: tree-dump.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) langhooks.h $(TOPLEV_H) $(SPLAY_TREE_H) $(TREE_DUMP_H) \ tree-iterator.h $(TREE_PASS_H) $(DIAGNOSTIC_H) $(REAL_H) fixed-value.h @@ -2357,7 +2432,7 @@ tree-ssa-address.o : tree-ssa-address.c $(TREE_FLOW_H) $(CONFIG_H) \ $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) \ output.h $(DIAGNOSTIC_H) $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ $(TREE_PASS_H) $(FLAGS_H) $(TREE_INLINE_H) $(RECOG_H) insn-config.h \ - $(EXPR_H) gt-tree-ssa-address.h $(GGC_H) tree-affine.h + $(EXPR_H) gt-tree-ssa-address.h $(GGC_H) tree-affine.h $(TARGET_H) tree-ssa-loop-niter.o : tree-ssa-loop-niter.c $(TREE_FLOW_H) $(CONFIG_H) \ $(SYSTEM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(CFGLOOP_H) $(PARAMS_H) \ $(TREE_INLINE_H) output.h $(DIAGNOSTIC_H) $(TM_H) coretypes.h $(TREE_DUMP_H) \ @@ -2572,7 +2647,8 @@ tree-object-size.o: tree-object-size.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TREE_PASS_H) tree-ssa-propagate.h gimple.o : gimple.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TREE_H) \ $(GGC_H) $(GIMPLE_H) $(TOPLEV_H) $(DIAGNOSTIC_H) gt-gimple.h \ - $(TREE_FLOW_H) value-prof.h $(FLAGS_H) $(DEMANGLE_H) + $(TREE_FLOW_H) value-prof.h $(FLAGS_H) $(DEMANGLE_H) \ + $(TARGET_H) $(ALIAS_H) gimple-pretty-print.o : gimple-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) $(DIAGNOSTIC_H) $(REAL_H) $(HASHTAB_H) $(TREE_FLOW_H) \ $(TM_H) coretypes.h $(TREE_PASS_H) $(GIMPLE_H) value-prof.h @@ -2640,7 +2716,7 @@ passes.o : passes.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ langhooks.h insn-flags.h $(CFGLAYOUT_H) $(REAL_H) $(CFGLOOP_H) \ hosthooks.h $(CGRAPH_H) $(COVERAGE_H) $(TREE_PASS_H) $(TREE_DUMP_H) \ $(GGC_H) $(INTEGRATE_H) $(CPPLIB_H) opts.h $(TREE_FLOW_H) $(TREE_INLINE_H) \ - gt-passes.h $(DF_H) $(PREDICT_H) + gt-passes.h $(DF_H) $(PREDICT_H) $(LTO_HEADER_H) $(LTO_SECTION_OUT_H) plugin.o : plugin.c $(PLUGIN_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TOPLEV_H) $(TREE_H) $(TREE_PASS_H) intl.h $(PLUGIN_VERSION_H) $(GGC_H) @@ -2669,7 +2745,8 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(RTL_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) hard-reg-set.h $(REGS_H) \ output.h $(TOPLEV_H) xcoffout.h debug.h $(GGC_H) $(TM_P_H) \ $(HASHTAB_H) $(TARGET_H) langhooks.h gt-varasm.h $(BASIC_BLOCK_H) \ - $(CFGLAYOUT_H) $(CGRAPH_H) targhooks.h tree-mudflap.h $(REAL_H) tree-iterator.h + $(CFGLAYOUT_H) $(CGRAPH_H) targhooks.h tree-mudflap.h $(REAL_H) \ + tree-iterator.h function.o : function.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(CFGLAYOUT_H) $(GIMPLE_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) \ $(OPTABS_H) libfuncs.h $(REGS_H) hard-reg-set.h insn-config.h $(RECOG_H) \ @@ -2747,7 +2824,7 @@ emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(TREE_H) $(FLAGS_H) $(FUNCTION_H) $(REGS_H) insn-config.h $(RECOG_H) \ $(GGC_H) $(EXPR_H) hard-reg-set.h $(BITMAP_H) $(TOPLEV_H) $(BASIC_BLOCK_H) \ $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h $(TREE_PASS_H) gt-emit-rtl.h \ - $(REAL_H) $(DF_H) $(PARAMS_H) + $(REAL_H) $(DF_H) $(PARAMS_H) $(TARGET_H) real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(TOPLEV_H) $(TM_P_H) $(REAL_H) dfp.h dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ @@ -2771,7 +2848,8 @@ simplify-rtx.o : simplify-rtx.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ langhooks.h $(TOPLEV_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \ - $(TREE_INLINE_H) $(TREE_DUMP_H) $(TREE_FLOW_H) value-prof.h $(EXCEPT_H) + $(TREE_INLINE_H) $(TREE_DUMP_H) $(TREE_FLOW_H) cif-code.def \ + value-prof.h $(EXCEPT_H) cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) langhooks.h $(TREE_INLINE_H) $(TOPLEV_H) $(FLAGS_H) $(GGC_H) \ $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(GIMPLE_H) \ @@ -2813,12 +2891,13 @@ ipa-reference.o : ipa-reference.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ pointer-set.h $(GGC_H) $(IPA_REFERENCE_H) $(IPA_UTILS_H) $(SPLAY_TREE_H) \ $(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) \ - $(TIMEVAR_H) $(DIAGNOSTIC_H) $(FUNCTION_H) gt-ipa-reference.h + $(TIMEVAR_H) $(DIAGNOSTIC_H) $(FUNCTION_H) gt-ipa-reference.h \ + $(LTO_STREAMER_H) ipa-pure-const.o : ipa-pure-const.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ pointer-set.h $(GGC_H) $(IPA_UTILS_H) $(TARGET_H) \ $(GIMPLE_H) $(CGRAPH_H) output.h $(FLAGS_H) $(TREE_PASS_H) $(TIMEVAR_H) \ - $(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H) + $(DIAGNOSTIC_H) $(CFGLOOP_H) $(SCEV_H) $(LTO_STREAMER_H) ipa-type-escape.o : ipa-type-escape.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) $(TREE_H) $(TREE_FLOW_H) $(TREE_INLINE_H) langhooks.h \ pointer-set.h $(GGC_H) $(IPA_TYPE_ESCAPE_H) $(IPA_UTILS_H) $(SPLAY_TREE_H) \ @@ -2955,7 +3034,7 @@ alloc-pool.o : alloc-pool.c $(CONFIG_H) $(SYSTEM_H) alloc-pool.h $(HASHTAB_H) auto-inc-dec.o : auto-inc-dec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(RTL_H) $(TM_P_H) hard-reg-set.h $(BASIC_BLOCK_H) insn-config.h \ $(REGS_H) $(FLAGS_H) output.h $(FUNCTION_H) $(EXCEPT_H) $(TOPLEV_H) $(RECOG_H) \ - $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) + $(EXPR_H) $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H) $(DBGCNT_H) $(TARGET_H) cfg.o : cfg.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(FLAGS_H) \ $(REGS_H) hard-reg-set.h output.h $(TOPLEV_H) $(FUNCTION_H) $(EXCEPT_H) $(GGC_H) \ $(TM_P_H) $(TIMEVAR_H) $(OBSTACK_H) $(TREE_H) alloc-pool.h \ @@ -2997,9 +3076,9 @@ loop-iv.o : loop-iv.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(BASIC_BLOCK_H) \ hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) coretypes.h $(TM_H) $(OBSTACK_H) \ output.h intl.h $(TOPLEV_H) $(DF_H) $(HASHTAB_H) loop-invariant.o : loop-invariant.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ - $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) $(RECOG_H) coretypes.h \ - $(TM_H) $(TM_P_H) $(FUNCTION_H) $(FLAGS_H) $(DF_H) $(OBSTACK_H) output.h \ - $(HASHTAB_H) $(EXCEPT_H) $(PARAMS_H) + $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(EXPR_H) $(RECOG_H) \ + coretypes.h $(TM_H) $(TM_P_H) $(FUNCTION_H) $(FLAGS_H) $(DF_H) \ + $(OBSTACK_H) output.h $(HASHTAB_H) $(EXCEPT_H) $(PARAMS_H) $(REGS_H) ira.h cfgloopmanip.o : cfgloopmanip.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) \ $(BASIC_BLOCK_H) hard-reg-set.h $(CFGLOOP_H) $(CFGLAYOUT_H) output.h \ coretypes.h $(TM_H) cfghooks.h $(OBSTACK_H) $(TREE_FLOW_H) @@ -3113,7 +3192,7 @@ ira.o: ira.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ regmove.o : regmove.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ insn-config.h $(TIMEVAR_H) $(TREE_PASS_H) $(DF_H)\ $(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \ - $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(EXCEPT_H) reload.h + $(EXPR_H) $(BASIC_BLOCK_H) $(TOPLEV_H) $(TM_P_H) $(EXCEPT_H) ira.h reload.h combine-stack-adj.o : combine-stack-adj.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(RTL_H) insn-config.h $(TIMEVAR_H) $(TREE_PASS_H) \ $(RECOG_H) output.h $(REGS_H) hard-reg-set.h $(FLAGS_H) $(FUNCTION_H) \ @@ -3136,7 +3215,7 @@ haifa-sched.o : haifa-sched.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_ sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ $(FUNCTION_H) $(INSN_ATTR_H) $(TOPLEV_H) $(RECOG_H) $(EXCEPT_H) cselib.h \ - ira.h $(PARAMS_H) $(TM_P_H) ira.h + ira.h $(PARAMS_H) $(TM_P_H) ira.h $(TARGET_H) sched-rgn.o : sched-rgn.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(SCHED_INT_H) $(REGS_H) hard-reg-set.h $(FLAGS_H) insn-config.h \ $(FUNCTION_H) $(INSN_ATTR_H) $(TOPLEV_H) $(RECOG_H) $(EXCEPT_H) $(PARAMS_H) \ @@ -3504,7 +3583,9 @@ GTFILES = $(CPP_ID_DATA_H) $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/tree-phinodes.c \ $(srcdir)/ipa-reference.c \ $(srcdir)/tree-ssa-structalias.c \ + $(srcdir)/lto-symtab.c \ $(srcdir)/tree-ssa-alias.h \ + $(srcdir)/ipa-prop.h \ @all_gtfiles@ # Compute the list of GT header files from the corresponding C sources, @@ -4145,7 +4226,7 @@ maintainer-clean: # broken is small. install: install-common $(INSTALL_HEADERS) \ install-cpp install-man install-info install-@POSUB@ \ - install-driver + install-driver install-lto-wrapper ifeq ($(enable_plugin),yes) install: install-plugin @@ -4179,7 +4260,8 @@ PLUGIN_HEADERS = $(TREE_H) $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(host_xm_file_list) $(host_xm_include_list) $(xm_include_list) \ intl.h $(PLUGIN_VERSION_H) $(DIAGNOSTIC_H) $(C_COMMON_H) $(C_PRETTY_PRINT_H) \ tree-iterator.h $(PLUGIN_H) $(TREE_FLOW_H) langhooks.h incpath.h \ - tree-ssa-sccvn.h real.h + tree-ssa-sccvn.h real.h output.h $(IPA_UTILS_H) \ + $(C_PRAGMA_H) $(CPPLIB_H) $(FUNCTION_H) # Install the headers needed to build a plugin. install-plugin: installdirs lang.install-plugin @@ -4440,6 +4522,10 @@ install-collect2: collect2 installdirs # Install the driver program as $(libsubdir)/gcc for collect2. $(INSTALL_PROGRAM) xgcc$(exeext) $(DESTDIR)$(libexecsubdir)/gcc$(exeext) +# Install lto-wrapper. +install-lto-wrapper: lto-wrapper$(exeext) + $(INSTALL_PROGRAM) lto-wrapper$(exeext) $(DESTDIR)$(libexecsubdir)/lto-wrapper$(exeext) + # Cancel installation by deleting the installed files. uninstall: lang.uninstall -rm -rf $(DESTDIR)$(libsubdir) @@ -4491,6 +4577,9 @@ site.exp: ./config.status Makefile echo "set ENABLE_PLUGIN 1" >> ./tmp0; \ echo "set GMPINC \"$(GMPINC)\"" >> ./tmp0; \ fi + @if test "@enable_lto@" = "yes" ; then \ + echo "set ENABLE_LTO 1" >> ./tmp0; \ + fi # If newlib has been configured, we need to pass -B to gcc so it can find # newlib's crt0.o if it exists. This will cause a "path prefix not used" # message if it doesn't, but the testsuite is supposed to ignore the message - diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog index 6520a7f4681..8c98429a2f3 100644 --- a/gcc/ada/ChangeLog +++ b/gcc/ada/ChangeLog @@ -1,3 +1,478 @@ +2009-11-05 Eric Botcazou + + * gcc-interface/utils.c (gnat_type_for_mode): Handle vector modes. + +2009-11-05 Eric Botcazou + + * gcc-interface/trans.c (lvalue_required_p) : + New case. + +2009-10-30 Eric Botcazou + + * gcc-interface/utils.c (MAX_FIXED_MODE_SIZE): Delete. + (create_field_decl): Update description. In a packed record, round + the size up to a byte boundary only if the field's type has BLKmode. + * gcc-interface/gigi.h (create_field_decl): Update description. + +2009-10-30 Emmanuel Briot + + * make.adb (Start_Compile_If_Possible): Compute location of resulting + ALI file in this procedure instead of after the compilation itself, + since the current directory might have changed in between when using + -j. + + * osint.ads: Addded missing alignment clause. + + * adaint.c, adaint.h, osint.adb (__gnat_reset_attributes, + __gnat_size_of_file_attributes): Rename reset_attributes and + size_of_file_attributes. + +2009-10-30 Javier Miranda + + * sem_scil.adb (Adjust_SCIL_Node): Add missing management of sequences + of statements when searching for SCIL nodes. + +2009-10-30 Tristan Gingold + + * gnatlink.adb, link.c: By default use shared libgcc on darwin. + +2009-10-30 Emmanuel Briot + + * make.adb, osint.adb (Add_Lib_Search_Dir): Do not add if dir is + already in the list. + This saves system calls when looking for ALI files + (Scan_Make_Args): The parameter to gnatmake's -D is now converted to an + absolute PATH (so that the above improvement properly occurs if both + -D and -aO are specified). + +2009-10-30 Thomas Quinot + + * a-direct.adb: Minor reformatting + +2009-10-30 Emmanuel Briot + + * make.adb, adaint.c, adaint.h, osint.adb, osint.ads, bcheck.adb + (*_attr): new subprograms. + (File_Length, File_Time_Stamp, Is_Writable_File): new subprograms + (Read_Library_Info_From_Full, Full_Library_Info_Name, + Full_Source_Name): Now benefit from a previous cache of the file + attributes, to further save on system calls. + (Smart_Find_File): now also cache the file attributes. This makes the + package File_Stamp_Hash_Table useless, and it was removed. + (Compile_Sources): create subprograms for the various steps of the main + loop, for readibility and to avoid sharing variables between the + various steps. + +2009-10-30 Emmanuel Briot + + * make.adb, osint.adb, osint.ads (Library_File_Stamp): Removed, since + unused. + (Read_Library_Info_From_Full): New subprogram. + +2009-10-30 Robert Dewar + + * a-tideio.adb: Minor reformatting + * a-wtdeio.adb, a-ztdeio.adb: Update comments, code clean up. + + * a-reatim.adb, a-tideau.adb, a-ngelfu.adb, a-ztdeau.adb, a-ngrear.adb, + a-wtedit.adb, a-ststio.adb, a-ztedit.adb: Minor code reorganization + (use conditional expressions). + +2009-10-30 Ed Schonberg + + * gnat_ugn.texi: Additional info on gnatw.i and gnatw.I + + * sem_case.adb: Improved error message. + +2009-10-30 Emmanuel Briot + + * a-direct.adb, gnatcmd.adb, gnatname.adb, makeutl.adb, opt.ads, + osint.adb, prj-ext.adb, switch-m.adb (Follow_Links_For_Dirs): Now + defaults to False, and controlled by -eL. + * a-direct.adb: Add comments. + * osint.adb (File_Stamp): Avoid unneeded duplicate system call + +2009-10-30 Robert Dewar + + * sem_res.adb (Resolve_Type_Conversion): Avoid false positive when + converting non-static subtype to "identical" static subtype. + +2009-10-30 Ed Schonberg + + * usage.adb: Add -gnatw.i switch. + +2009-10-30 Vincent Celier + + * xsnamest.adb: Update comments with regards to the template files + snames.*.tmpl + +2009-10-30 Bob Duff + + * s-fileio.adb (Errno_Message): Suppress VMS-specific warning. + +2009-10-30 Ed Schonberg + + * sem_case.adb (Check_Choices): Add explanatory message when there are + missing alternatives when the required range of alternatives is given + by the base type of the case expression or discriminant in a variant + part. + + * opt.ads: New flag Warn_On_Overlap, to enable warnings on potentially + dangerous overlap between actuals in a call, activated by -gnatw.i + * sem_warn.adb (Set_Dot_Warning_Switch): set flag. + (Warn_On_Overlapping_Actuals): use new flag. + + * gnat_ugn.texi: Document -gnatw.i, warning on overlapping actuals + +2009-10-30 Robert Dewar + + * exp_aggr.adb, exp_ch9.adb: Minor reformatting + +2009-10-29 Eric Botcazou + + * gcc-interface/decl.c (make_type_from_size) : Do not + create integer types with precision 0. + +2009-10-29 Eric Botcazou + + PR ada/41870 + * gcc-interface/decl.c (array_type_has_nonaliased_component): Swap + parameters and rewrite comments. For a derived type, return the + setting of its parent type. + (gnat_to_gnu_entity): Do an alias set copy for derived types if they + are composite. Adjust calls to above function. + +2009-10-29 Eric Botcazou + + * gcc-interface/trans.c (Attribute_to_gnu) : Do not + return the RM size for padded types. + +2009-10-28 Robert Dewar + + * sem_type.adb: Minor reformatting + +2009-10-28 Arnaud Charlet + + * exp_ch9.adb (Build_Task_Proc_Specification): Generate a different + suffix for task type bodies. + +2009-10-28 Ed Schonberg + + * exp_aggr.adb (Convert_Aggr_In_Allocator): Do not look for a + finalization list if the designated type requires no control actions, + to prevent a useless semantic dependence on ada.tags. + +2009-10-28 Bob Duff + + * s-fileio.adb: Give more information in exception messages. + +2009-10-28 Robert Dewar + + * gnat_ugn.texi: Document new -gnatyt requirement for space after right + paren if next token starts with digit or letter. + * styleg.adb (Check_Right_Paren): New rule for space after if next + character is a letter or digit. + +2009-10-28 Thomas Quinot + + * s-crtl.ads (System.CRTL.strerror): New function. + +2009-10-28 Ed Schonberg + + * sem_type.adb: Add guard to recover some type errors. + +2009-10-28 Vincent Celier + + * prj-nmsc.adb (Add_To_Or_Remove_From_List): New name of procedure + Add_If_Not_In_List to account to the fact that a directory may be + removed from the list. Only remove directory if Removed is True. + +2009-10-28 Gary Dismukes + + * a-textio.ads, a-textio.ads: Put back function EOF_Char in private + part. Put back body of function EOF_Char. + * a-tienau.adb: Remove with of Interfaces.C_Streams and change EOF back + to EOF_Char. + +2009-10-28 Emmanuel Briot + + * prj-tree.adb (Free): Fix memory leak. + +2009-10-28 Thomas Quinot + + * s-fileio.adb: Minor reformatting + +2009-10-28 Arnaud Charlet + + * gcc-interface/Make-lang.in: Update dependencies. + +2009-10-28 Robert Dewar + + * exp_attr.adb, exp_ch9.adb, prj-nmsc.adb, tbuild.adb, ali.adb, + types.ads: Minor reformatting + +2009-10-28 Tristan Gingold + + * init.c: Fix __gnat_error_handler for Darwin10 (Snow Leopard) + +2009-10-28 Thomas Quinot + + * exp_ch4.adb (Expand_N_Type_Conversion): Perform Integer promotion for + the operand of the unary minus and ABS operators. + + * sem_type.adb (Covers): A concurrent type and its corresponding record + type are compatible. + * exp_attr.adb (Expand_N_Attribute_Reference): Do not rewrite a 'Access + attribute reference for the current instance of a protected type while + analyzing an access discriminant constraint in a component definition. + Such a reference is handled in the corresponding record's init proc, + while initializing the constrained component. + * exp_ch9.adb (Expand_N_Protected_Type_Declaration): When creating the + corresponding record type, propagate components' + Has_Per_Object_Constraint flag. + * exp_ch3.adb (Build_Init_Procedure.Build_Init_Statements): + For a concurrent type, set up concurrent aspects before initializing + components with a per object constrain, because they may be controlled, + and their initialization may call entries or protected subprograms of + the enclosing concurrent object. + +2009-10-28 Emmanuel Briot + + * prj-nmsc.adb (Add_If_Not_In_List): New subprogram, for better sharing + of code. + (Find_Source_Dirs): resolve links if Opt.Follow_Links_For_Dirs when + processing the directories specified explicitly in the project file. + +2009-10-28 Robert Dewar + + * a-ztexio.adb, a-ztexio.ads, a-witeio.ads, a-witeio.adb, + a-textio.ads, a-textio.adb: Reorganize (moving specs from private part + to body). + (Initialize_Standard_Files): New procedure. + * a-tienau.adb: Minor change to make EOF directly visible + * a-tirsfi.ads, a-wrstfi.adb, a-wrstfi.ads, a-zrstfi.adb, + a-zrstfi.ads, a-tirsfi.adb: New unit, initial version. + * gnat_rm.texi: Add documentation for + Ada.[Wide_[Wide_]]Text_IO.Reset_Standard_Files. + * Makefile.rtl: Add entries for + Ada.[Wide_[Wide_]]Text_IO.Reset_Standard_Files + +2009-10-28 Thomas Quinot + + * exp_ch9.ads: Minor reformatting + * sem_ch3.adb: Minor reformatting + * sem_aggr.adb: Minor reformatting. + * sem_attr.adb: Minor reformatting + * tbuild.adb, tbuild.ads, par-ch4.adb, exp_ch4.adb (Tbuild.New_Op_Node): + New subprogram. + Minor code reorganization/factoring. + +2009-10-27 Eric Botcazou + + * gcc-interface/decl.c (purpose_member_field): New static function. + (annotate_rep): Use it instead of purpose_member. + +2009-10-27 Eric Botcazou + + * raise-gcc (db_region_for): Use _Unwind_GetIPInfo instead of + _Unwind_GetIP if HAVE_GETIPINFO is defined. + (db_action_for): Likewise. + +2009-10-27 Robert Dewar + + * s-fileio.adb, s-fileio.ads, sem_util.adb, sem_warn.adb, + sem_warn.ads: Minor reformatting + +2009-10-27 Robert Dewar + + * sem_warn.adb, sem_util.adb, sem_util.ads: Minor reformatting. Add + comments. + +2009-10-27 Robert Dewar + + * s-os_lib.ads, s-os_lib.adb, prj-err.adb, makeutl.adb: Minor + reformatting. + +2009-10-27 Ed Schonberg + + * sem.util.ads, sem_util.adb (Denotes_Same_Object, + Denotes_Same_Prefix): New functions to detect overlap between actuals + that are not by-copy in a call, when one of them is in-out. + * sem_warn.ads, sem_warn.adb (Warn_On_Overlapping_Actuals): New + procedure, called on a subprogram call to warn when an in-out actual + that is not by-copy overlaps with another actual, thus leadind to + potentially dangerous aliasing in the body of the called subprogram. + Currently the warning is under control of the -gnatX switch. + * sem_res.adb (resolve_call): call Warn_On_Overlapping_Actuals. + +2009-10-27 Thomas Quinot + + * sem_ch12.adb (Install_Formal_Packages): Do not omit installation of + visible entities when the formal package doesn't have a box. + + * checks.adb: Minor reformatting. + +2009-10-27 Vincent Celier + + * prj-part.adb (Parse): Catch exception Types.Unrecoverable_Error and + set Project to Empty_Node. + +2009-10-27 Robert Dewar + + * gnatbind.adb: Minor reformatting + +2009-10-27 Arnaud Charlet + + * exp_aggr.adb: Fix comment. + +2009-10-27 Emmanuel Briot + + * prj-err.adb (Error_Msg): take into account continuation lines when + computing whether we have a warning. + +2009-10-27 Vasiliy Fofanov + + * make.adb, s-os_lib.adb, s-os_lib.ads (Create_Temp_Output_File): New + routine that is designed to create temp file descriptor specifically + for redirecting an output stream. + +2009-10-24 Eric Botcazou + + * gcc-interface/decl.c (gnat_to_gnu_entity) : When + processing the parent type, build the COMPONENT_REF for a discriminant + with the proper type. + +2009-10-24 Eric Botcazou + + * init.c (__gnat_adjust_context_for_raise): Mention _Unwind_GetIPInfo. + * gcc-interface/Makefile.in (GNATLIBCFLAGS_FOR_C): Add HAVE_GETIPINFO. + Pass GNATLIBCFLAGS_FOR_C to recursive invocations. + +2009-10-21 Eric Botcazou + + * gcc-interfaces/decl.c (build_subst_list): Convert the expression of + the constraint to the type of the discriminant. + +2009-10-21 Eric Botcazou + + * gcc-interfaces/decl.c (gnat_to_gnu_entity): Do not create a new + TYPE_DECL when a type is padded if there is already one and reset + TYPE_STUB_DECL in this case. + +2009-10-21 Eric Botcazou + + * gcc-interfaces/utils.c (create_subprog_decl): Do not redefine + main_identifier_node. + +2009-10-17 Eric Botcazou + + * gcc-interface/utils.c (convert): When converting to a padded type + with an inner type of self-referential size, pad the expression before + doing the unchecked conversion. + +2009-10-17 Eric Botcazou + + * gcc-interface/utils2.c (build_binary_op) : Make + sure the element type is consistent. + +2009-10-17 Eric Botcazou + + * gcc-interface/trans.c (addressable_p): Handle bitwise operations. + +2009-10-16 Eric Botcazou + + * gcc-interface/ada-tree.h (TYPE_FAT_POINTER_P): Swap with... + (TYPE_IS_FAT_POINTER_P): ...this. + (TYPE_THIN_POINTER_P): Rename into... + (TYPE_IS_THIN_POINTER_P): ...this. + (TYPE_FAT_OR_THIN_POINTER_P): Rename into... + (TYPE_IS_FAT_OR_THIN_POINTER_P): ...this. + (TYPE_IS_PADDING_P): Change definition, move old one to... + (TYPE_PADDING_P): ...this. + * gcc-interface/decl.c (gnat_to_gnu_entity): Adjust for above changes. + (get_unpadded_type): Likewise. + (gnat_to_gnu_component_type): Likewise. + (gnat_to_gnu_param): Likewise. + (relate_alias_sets): Likewise. + (make_packable_type): Likewise. + (maybe_pad_type): Likewise. + (gnat_to_gnu_field): Likewise. + (is_variable_size): Likewise. + (annotate_object): Likewise. + (validate_size): Likewise. + (set_rm_size): Likewise. + (make_type_from_size): Likewise. + (rm_size): Likewise. + * gcc-interface/misc.c (gnat_print_type): Likewise. + (gnat_get_alias_set): Likewise. + * gcc-interface/trans.c (Identifier_to_gnu): Likewise. + (Attribute_to_gnu): Likewise. + (call_to_gnu): Likewise. + (gnat_to_gnu): Likewise. + (add_decl_expr): Likewise. + (convert_with_check): Likewise. + (addressable_p): Likewise. + (maybe_implicit_deref): Likewise. + (protect_multiple_eval): Likewise. + (gnat_stabilize_reference_1): Likewise. + * gcc-interface/utils.c (gnat_pushdecl): Likewise. + (finish_record_type): Likewise. + (rest_of_record_type_compilation): Likewise. + (create_type_decl): Likewise. + (gnat_types_compatible_p): Likewise. + (build_template): Likewise. + (convert_vms_descriptor64): Likewise. + (convert_vms_descriptor32): Likewise. + (build_unc_object_type_from_ptr): Likewise. + (update_pointer_to): Likewise. + (convert_to_fat_pointer): Likewise. + (convert_to_fat_pointer): Likewise. + (convert): Likewise. + (remove_conversions): Likewise. + (maybe_unconstrained_array): Likewise. + (unchecked_convert): Likewise. + (handle_vector_type_attribute): Likewise. + * gcc-interface/utils2.c (build_binary_op): Likewise. + (build_unary_op): Likewise. + (build_allocator): Likewise. + +2009-10-16 Eric Botcazou + + * exp_dbug.ads: Adjust type names in comments. + * gcc-interface/decl.c (maybe_pad_type): Remove NAME_TRAILER parameter, + add new IS_COMPONENT_TYPE parameter. Adjust. Remove dead code. + (gnat_to_gnu_entity): Adjust for above change. + (gnat_to_gnu_component_type): Likewise. + (gnat_to_gnu_field): Likewise. + * gcc-interface/trans.c (call_to_gnu): Likewise. Do not unnecessarily + call max_size. + * gcc-interface/utils.c (finish_record_type): Remove obsolete code. + * gcc-interface/gigi.h (maybe_pad_type): Adjust prototype. + +2009-10-16 Joel Sherrill + + * s-osinte-rtems.ads: Add mutex type to pthread_mutexattr_t + * s-stchop-rtems.adb: Correct binding to rtems_stack_checker_is_blown. + +2009-10-13 Rainer Orth + + * env.c [__alpha__ && __osf__] (AES_SOURCE): Define. + +2009-10-10 Samuel Tardieu + + * sem_eval.adb: Give a more precise error message. + +2009-10-06 Samuel Tardieu + + PR ada/41383 + * a-rttiev.adb (Time_Of_Event): Return Time_First for unset event. + +2009-10-06 Samuel Tardieu + + PR ada/38333 + * sem_prag.adb (Process_Import_Or_Interface): Forbid an abstract + subprogram to be completed with a "pragma Import". + 2009-10-02 Eric Botcazou * gcc-interface/decl.c (gnat_to_gnu_entity) : diff --git a/gcc/ada/Makefile.rtl b/gcc/ada/Makefile.rtl index 5f06d1cf2e8..4f26f1569b5 100644 --- a/gcc/ada/Makefile.rtl +++ b/gcc/ada/Makefile.rtl @@ -258,6 +258,7 @@ GNATRTL_NONTASKING_OBJS= \ a-timoau$(objext) \ a-timoio$(objext) \ a-tiocst$(objext) \ + a-tirsfi$(objext) \ a-titest$(objext) \ a-tiunio$(objext) \ a-unccon$(objext) \ @@ -265,6 +266,7 @@ GNATRTL_NONTASKING_OBJS= \ a-wichun$(objext) \ a-widcha$(objext) \ a-witeio$(objext) \ + a-wrstfi$(objext) \ a-wtcoau$(objext) \ a-wtcoio$(objext) \ a-wtcstr$(objext) \ @@ -286,6 +288,7 @@ GNATRTL_NONTASKING_OBJS= \ a-wwunio$(objext) \ a-zchara$(objext) \ a-zchuni$(objext) \ + a-zrstfi$(objext) \ a-ztcoau$(objext) \ a-ztcoio$(objext) \ a-ztcstr$(objext) \ diff --git a/gcc/ada/a-direct.adb b/gcc/ada/a-direct.adb index f0182c68e7a..1013b1514db 100644 --- a/gcc/ada/a-direct.adb +++ b/gcc/ada/a-direct.adb @@ -210,6 +210,9 @@ package body Ada.Directories is else declare + -- We need to resolve links because of A.16(47), since we must not + -- return alternative names for files. + Norm : constant String := Normalize_Pathname (Name); Last_DS : constant Natural := Strings.Fixed.Index @@ -441,6 +444,8 @@ package body Ada.Directories is Local_Get_Current_Dir (Buffer'Address, Path_Len'Address); declare + -- We need to resolve links because of A.16(47), since we must not + -- return alternative names for files Cur : constant String := Normalize_Pathname (Buffer (1 .. Path_Len)); begin @@ -781,6 +786,8 @@ package body Ada.Directories is -- Use System.OS_Lib.Normalize_Pathname declare + -- We need to resolve links because of A.16(47), since we must not + -- return alternative names for files Value : constant String := Normalize_Pathname (Name); subtype Result is String (1 .. Value'Length); begin diff --git a/gcc/ada/a-ngelfu.adb b/gcc/ada/a-ngelfu.adb index ef9aadd4306..55d14e7db53 100644 --- a/gcc/ada/a-ngelfu.adb +++ b/gcc/ada/a-ngelfu.adb @@ -729,21 +729,12 @@ package body Ada.Numerics.Generic_Elementary_Functions is Raw_Atan : Float_Type'Base; begin - if abs Y > abs X then - Z := abs (X / Y); - else - Z := abs (Y / X); - end if; - - if Z < Sqrt_Epsilon then - Raw_Atan := Z; + Z := (if abs Y > abs X then abs (X / Y) else abs (Y / X)); - elsif Z = 1.0 then - Raw_Atan := Pi / 4.0; - - else - Raw_Atan := Float_Type'Base (Aux.Atan (Double (Z))); - end if; + Raw_Atan := + (if Z < Sqrt_Epsilon then Z + elsif Z = 1.0 then Pi / 4.0 + else Float_Type'Base (Aux.Atan (Double (Z)))); if abs Y > abs X then Raw_Atan := Half_Pi - Raw_Atan; diff --git a/gcc/ada/a-ngrear.adb b/gcc/ada/a-ngrear.adb index b0cf3e1fd72..5c8a0092477 100644 --- a/gcc/ada/a-ngrear.adb +++ b/gcc/ada/a-ngrear.adb @@ -433,11 +433,7 @@ package body Ada.Numerics.Generic_Real_Arrays is end if; for J in 1 .. N loop - if Piv (J) /= J then - Det := -Det * LU (J, J); - else - Det := Det * LU (J, J); - end if; + Det := (if Piv (J) /= J then -Det * LU (J, J) else Det * LU (J, J)); end loop; return Det; diff --git a/gcc/ada/a-reatim.adb b/gcc/ada/a-reatim.adb index 2ca4472a5ea..c3cbec69ddc 100644 --- a/gcc/ada/a-reatim.adb +++ b/gcc/ada/a-reatim.adb @@ -7,7 +7,7 @@ -- B o d y -- -- -- -- Copyright (C) 1991-1994, Florida State University -- --- Copyright (C) 1995-2006, AdaCore -- +-- Copyright (C) 1995-2009, AdaCore -- -- -- -- GNARL is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -189,19 +189,12 @@ package body Ada.Real_Time is -- Special-case for Time_First, whose absolute value is anomalous, -- courtesy of two's complement. - if T = Time_First then - T_Val := abs (Time_Last); - else - T_Val := abs (T); - end if; + T_Val := (if T = Time_First then abs (Time_Last) else abs (T)); -- Extract the integer part of T, truncating towards zero - if T_Val < 0.5 then - SC := 0; - else - SC := Seconds_Count (Time_Span'(T_Val - 0.5)); - end if; + SC := + (if T_Val < 0.5 then 0 else Seconds_Count (Time_Span'(T_Val - 0.5))); if T < 0.0 then SC := -SC; diff --git a/gcc/ada/a-rttiev.adb b/gcc/ada/a-rttiev.adb index 2068c786850..55687ec8f6b 100644 --- a/gcc/ada/a-rttiev.adb +++ b/gcc/ada/a-rttiev.adb @@ -332,7 +332,13 @@ package body Ada.Real_Time.Timing_Events is function Time_Of_Event (Event : Timing_Event) return Time is begin - return Event.Timeout; + -- RM D.15(18/2): Time_First must be returned if the event is not set + + if Event.Handler = null then + return Time_First; + else + return Event.Timeout; + end if; end Time_Of_Event; -------------- diff --git a/gcc/ada/a-ststio.adb b/gcc/ada/a-ststio.adb index cf2f4ea2ee2..79ee6cdfd5a 100644 --- a/gcc/ada/a-ststio.adb +++ b/gcc/ada/a-ststio.adb @@ -241,11 +241,7 @@ package body Ada.Streams.Stream_IO is -- (and furthermore there are situations (such as the case of writing -- a sequential Posix FIFO file) where the lseek would cause problems. - if Mode = Out_File then - File.Last_Op := Op_Write; - else - File.Last_Op := Op_Read; - end if; + File.Last_Op := (if Mode = Out_File then Op_Write else Op_Read); end Open; ---------- diff --git a/gcc/ada/a-textio.adb b/gcc/ada/a-textio.adb index b3a98fcb3ec..ceacfe5b127 100644 --- a/gcc/ada/a-textio.adb +++ b/gcc/ada/a-textio.adb @@ -57,15 +57,30 @@ package body Ada.Text_IO is WC_Encoding : Character; pragma Import (C, WC_Encoding, "__gl_wc_encoding"); + -- Default wide character encoding + + Err_Name : aliased String := "*stderr" & ASCII.NUL; + In_Name : aliased String := "*stdin" & ASCII.NUL; + Out_Name : aliased String := "*stdout" & ASCII.NUL; + -- Names of standard files + -- + -- Use "preallocated" strings to avoid calling "new" during the elaboration + -- of the run time. This is needed in the tasking case to avoid calling + -- Task_Lock too early. A filename is expected to end with a null character + -- in the runtime, here the null characters are added just to have a + -- correct filename length. + -- + -- Note: the names for these files are bogus, and probably it would be + -- better for these files to have no names, but the ACVC tests insist! + -- We use names that are bound to fail in open etc. + + Null_Str : aliased constant String := ""; + -- Used as form string for standard files ----------------------- -- Local Subprograms -- ----------------------- - function Getc_Immed (File : File_Type) return int; - -- This routine is identical to Getc, except that the read is done in - -- Get_Immediate mode (i.e. without waiting for a line return). - function Get_Upper_Half_Char (C : Character; File : File_Type) return Character; @@ -82,18 +97,48 @@ package body Ada.Text_IO is -- This routine is identical to Get_Upper_Half_Char, except that the reads -- are done in Get_Immediate mode (i.e. without waiting for a line return). + function Getc (File : File_Type) return int; + -- Gets next character from file, which has already been checked for being + -- in read status, and returns the character read if no error occurs. The + -- result is EOF if the end of file was read. + + function Getc_Immed (File : File_Type) return int; + -- This routine is identical to Getc, except that the read is done in + -- Get_Immediate mode (i.e. without waiting for a line return). + function Has_Upper_Half_Character (Item : String) return Boolean; -- Returns True if any of the characters is in the range 16#80#-16#FF# + function Nextc (File : File_Type) return int; + -- Returns next character from file without skipping past it (i.e. it is a + -- combination of Getc followed by an Ungetc). + procedure Put_Encoded (File : File_Type; Char : Character); -- Called to output a character Char to the given File, when the encoding -- method for the file is other than brackets, and Char is upper half. + procedure Putc (ch : int; File : File_Type); + -- Outputs the given character to the file, which has already been checked + -- for being in output status. Device_Error is raised if the character + -- cannot be written. + procedure Set_WCEM (File : in out File_Type); -- Called by Open and Create to set the wide character encoding method for -- the file, processing a WCEM form parameter if one is present. File is -- IN OUT because it may be closed in case of an error. + procedure Terminate_Line (File : File_Type); + -- If the file is in Write_File or Append_File mode, and the current line + -- is not terminated, then a line terminator is written using New_Line. + -- Note that there is no Terminate_Page routine, because the page mark at + -- the end of the file is implied if necessary. + + procedure Ungetc (ch : int; File : File_Type); + -- Pushes back character into stream, using ungetc. The caller has checked + -- that the file is in read status. Device_Error is raised if the character + -- cannot be pushed back. An attempt to push back and end of file character + -- (EOF) is ignored. + ------------------- -- AFCB_Allocate -- ------------------- @@ -965,6 +1010,52 @@ package body Ada.Text_IO is return False; end Has_Upper_Half_Character; + ------------------------------- + -- Initialize_Standard_Files -- + ------------------------------- + + procedure Initialize_Standard_Files is + begin + Standard_Err.Stream := stderr; + Standard_Err.Name := Err_Name'Access; + Standard_Err.Form := Null_Str'Unrestricted_Access; + Standard_Err.Mode := FCB.Out_File; + Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0; + Standard_Err.Is_Temporary_File := False; + Standard_Err.Is_System_File := True; + Standard_Err.Is_Text_File := True; + Standard_Err.Access_Method := 'T'; + Standard_Err.Self := Standard_Err; + Standard_Err.WC_Method := Default_WCEM; + + Standard_In.Stream := stdin; + Standard_In.Name := In_Name'Access; + Standard_In.Form := Null_Str'Unrestricted_Access; + Standard_In.Mode := FCB.In_File; + Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0; + Standard_In.Is_Temporary_File := False; + Standard_In.Is_System_File := True; + Standard_In.Is_Text_File := True; + Standard_In.Access_Method := 'T'; + Standard_In.Self := Standard_In; + Standard_In.WC_Method := Default_WCEM; + + Standard_Out.Stream := stdout; + Standard_Out.Name := Out_Name'Access; + Standard_Out.Form := Null_Str'Unrestricted_Access; + Standard_Out.Mode := FCB.Out_File; + Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0; + Standard_Out.Is_Temporary_File := False; + Standard_Out.Is_System_File := True; + Standard_Out.Is_Text_File := True; + Standard_Out.Access_Method := 'T'; + Standard_Out.Self := Standard_Out; + Standard_Out.WC_Method := Default_WCEM; + + FIO.Make_Unbuffered (AP (Standard_Out)); + FIO.Make_Unbuffered (AP (Standard_Err)); + end Initialize_Standard_Files; + ------------- -- Is_Open -- ------------- @@ -2198,20 +2289,8 @@ package body Ada.Text_IO is end if; end Write; - -- Use "preallocated" strings to avoid calling "new" during the - -- elaboration of the run time. This is needed in the tasking case to - -- avoid calling Task_Lock too early. A filename is expected to end with a - -- null character in the runtime, here the null characters are added just - -- to have a correct filename length. - - Err_Name : aliased String := "*stderr" & ASCII.NUL; - In_Name : aliased String := "*stdin" & ASCII.NUL; - Out_Name : aliased String := "*stdout" & ASCII.NUL; - begin - ------------------------------- - -- Initialize Standard Files -- - ------------------------------- + -- Initialize Standard Files for J in WC_Encoding_Method loop if WC_Encoding = WC_Encoding_Letters (J) then @@ -2219,51 +2298,10 @@ begin end if; end loop; - -- Note: the names in these files are bogus, and probably it would be - -- better for these files to have no names, but the ACVC test insist! - -- We use names that are bound to fail in open etc. - - Standard_Err.Stream := stderr; - Standard_Err.Name := Err_Name'Access; - Standard_Err.Form := Null_Str'Unrestricted_Access; - Standard_Err.Mode := FCB.Out_File; - Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0; - Standard_Err.Is_Temporary_File := False; - Standard_Err.Is_System_File := True; - Standard_Err.Is_Text_File := True; - Standard_Err.Access_Method := 'T'; - Standard_Err.Self := Standard_Err; - Standard_Err.WC_Method := Default_WCEM; - - Standard_In.Stream := stdin; - Standard_In.Name := In_Name'Access; - Standard_In.Form := Null_Str'Unrestricted_Access; - Standard_In.Mode := FCB.In_File; - Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0; - Standard_In.Is_Temporary_File := False; - Standard_In.Is_System_File := True; - Standard_In.Is_Text_File := True; - Standard_In.Access_Method := 'T'; - Standard_In.Self := Standard_In; - Standard_In.WC_Method := Default_WCEM; - - Standard_Out.Stream := stdout; - Standard_Out.Name := Out_Name'Access; - Standard_Out.Form := Null_Str'Unrestricted_Access; - Standard_Out.Mode := FCB.Out_File; - Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0; - Standard_Out.Is_Temporary_File := False; - Standard_Out.Is_System_File := True; - Standard_Out.Is_Text_File := True; - Standard_Out.Access_Method := 'T'; - Standard_Out.Self := Standard_Out; - Standard_Out.WC_Method := Default_WCEM; + Initialize_Standard_Files; FIO.Chain_File (AP (Standard_In)); FIO.Chain_File (AP (Standard_Out)); FIO.Chain_File (AP (Standard_Err)); - FIO.Make_Unbuffered (AP (Standard_Out)); - FIO.Make_Unbuffered (AP (Standard_Err)); - end Ada.Text_IO; diff --git a/gcc/ada/a-textio.ads b/gcc/ada/a-textio.ads index 9277ccbbae5..d22b2f9c635 100644 --- a/gcc/ada/a-textio.ads +++ b/gcc/ada/a-textio.ads @@ -41,6 +41,7 @@ with Ada.IO_Exceptions; with Ada.Streams; + with System; with System.File_Control_Block; with System.WCh_Con; @@ -443,9 +444,6 @@ private -- The Standard Files -- ------------------------ - Null_Str : aliased constant String := ""; - -- Used as name and form of standard files - Standard_In_AFCB : aliased Text_AFCB; Standard_Out_AFCB : aliased Text_AFCB; Standard_Err_AFCB : aliased Text_AFCB; @@ -460,47 +458,15 @@ private Current_Err : aliased File_Type := Standard_Err; -- Current files - ----------------------- - -- Local Subprograms -- - ----------------------- - - -- These subprograms are in the private part of the spec so that they can - -- be shared by the routines in the body of Ada.Text_IO.Wide_Text_IO. - - -- Note: we use Integer in these declarations instead of the more accurate - -- Interfaces.C_Streams.int, because we do not want to drag in the spec of - -- this interfaces package with the spec of Ada.Text_IO, and we know that - -- in fact these types are identical - function EOF_Char return Integer; -- Returns the system-specific character indicating the end of a text file. -- This is exported for use by child packages such as Enumeration_Aux to - -- eliminate their needing to depend directly on Interfaces.C_Streams. - - function Getc (File : File_Type) return Integer; - -- Gets next character from file, which has already been checked for - -- being in read status, and returns the character read if no error - -- occurs. The result is EOF if the end of file was read. - - function Nextc (File : File_Type) return Integer; - -- Returns next character from file without skipping past it (i.e. it - -- is a combination of Getc followed by an Ungetc). - - procedure Putc (ch : Integer; File : File_Type); - -- Outputs the given character to the file, which has already been - -- checked for being in output status. Device_Error is raised if the - -- character cannot be written. - - procedure Terminate_Line (File : File_Type); - -- If the file is in Write_File or Append_File mode, and the current - -- line is not terminated, then a line terminator is written using - -- New_Line. Note that there is no Terminate_Page routine, because - -- the page mark at the end of the file is implied if necessary. - - procedure Ungetc (ch : Integer; File : File_Type); - -- Pushes back character into stream, using ungetc. The caller has - -- checked that the file is in read status. Device_Error is raised - -- if the character cannot be pushed back. An attempt to push back - -- and end of file character (EOF) is ignored. + -- eliminate their needing to depend directly on Interfaces.C_Streams, + -- which is not available in certain target environments (such as AAMP). + + procedure Initialize_Standard_Files; + -- Initializes the file control blocks for the standard files. Called from + -- the elaboration routine for this package, and from Reset_Standard_Files + -- in package Ada.Text_IO.Reset_Standard_Files. end Ada.Text_IO; diff --git a/gcc/ada/a-tideau.adb b/gcc/ada/a-tideau.adb index 298507a5c2c..2790bed68d7 100644 --- a/gcc/ada/a-tideau.adb +++ b/gcc/ada/a-tideau.adb @@ -242,11 +242,8 @@ package body Ada.Text_IO.Decimal_Aux is Ptr : Natural := 0; begin - if Exp = 0 then - Fore := To'Length - 1 - Aft; - else - Fore := To'Length - 2 - Aft - Exp; - end if; + Fore := + (if Exp = 0 then To'Length - 1 - Aft else To'Length - 2 - Aft - Exp); if Fore < 1 then raise Layout_Error; diff --git a/gcc/ada/a-tideio.adb b/gcc/ada/a-tideio.adb index 9db04784b95..5dceb128f90 100644 --- a/gcc/ada/a-tideio.adb +++ b/gcc/ada/a-tideio.adb @@ -51,7 +51,6 @@ package body Ada.Text_IO.Decimal_IO is begin if Num'Size > Integer'Size then Item := Num'Fixed_Value (Aux.Get_LLD (File, Width, Scale)); - else Item := Num'Fixed_Value (Aux.Get_Dec (File, Width, Scale)); end if; diff --git a/gcc/ada/a-tirsfi.adb b/gcc/ada/a-tirsfi.adb new file mode 100755 index 00000000000..791c066bab3 --- /dev/null +++ b/gcc/ada/a-tirsfi.adb @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- A D A . T E X T _ I O . R E S E T _ S T A N D A R D _ F I L E S -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-------------------------------------- +-- Ada.Text_IO.Reset_Standard_Files -- +-------------------------------------- + +procedure Ada.Text_IO.Reset_Standard_Files is +begin + Ada.Text_IO.Initialize_Standard_Files; +end Ada.Text_IO.Reset_Standard_Files; diff --git a/gcc/ada/a-tirsfi.ads b/gcc/ada/a-tirsfi.ads new file mode 100755 index 00000000000..b3d4ab0afb9 --- /dev/null +++ b/gcc/ada/a-tirsfi.ads @@ -0,0 +1,40 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- A D A . T E X T _ I O . R E S E T _ S T A N D A R D _ F I L E S -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This package provides a reset routine that resets the standard files used +-- by Text_IO. This is useful in systems such as VxWorks where Ada.Text_IO is +-- elaborated at the program start, but a system restart may alter the status +-- of these files, resulting in incorrect operation of Text_IO (in particular +-- if the standard input file is changed to be interactive, then Get_Line may +-- hang looking for an extra character after the end of the line. + +procedure Ada.Text_IO.Reset_Standard_Files; +-- Reset standard Text_IO files as described above diff --git a/gcc/ada/a-wichun.adb b/gcc/ada/a-wichun.adb old mode 100755 new mode 100644 diff --git a/gcc/ada/a-wichun.ads b/gcc/ada/a-wichun.ads old mode 100755 new mode 100644 diff --git a/gcc/ada/a-widcha.ads b/gcc/ada/a-widcha.ads old mode 100755 new mode 100644 diff --git a/gcc/ada/a-witeio.adb b/gcc/ada/a-witeio.adb index e877405820f..efd5021849d 100644 --- a/gcc/ada/a-witeio.adb +++ b/gcc/ada/a-witeio.adb @@ -57,26 +57,62 @@ package body Ada.Wide_Text_IO is WC_Encoding : Character; pragma Import (C, WC_Encoding, "__gl_wc_encoding"); + -- Default wide character encoding + + Err_Name : aliased String := "*stderr" & ASCII.NUL; + In_Name : aliased String := "*stdin" & ASCII.NUL; + Out_Name : aliased String := "*stdout" & ASCII.NUL; + -- Names of standard files + -- + -- Use "preallocated" strings to avoid calling "new" during the elaboration + -- of the run time. This is needed in the tasking case to avoid calling + -- Task_Lock too early. A filename is expected to end with a null character + -- in the runtime, here the null characters are added just to have a + -- correct filename length. + -- + -- Note: the names for these files are bogus, and probably it would be + -- better for these files to have no names, but the ACVC tests insist! + -- We use names that are bound to fail in open etc. + + Null_Str : aliased constant String := ""; + -- Used as form string for standard files ----------------------- -- Local Subprograms -- ----------------------- - function Getc_Immed (File : File_Type) return int; - -- This routine is identical to Getc, except that the read is done in - -- Get_Immediate mode (i.e. without waiting for a line return). - function Get_Wide_Char_Immed (C : Character; File : File_Type) return Wide_Character; -- This routine is identical to Get_Wide_Char, except that the reads are -- done in Get_Immediate mode (i.e. without waiting for a line return). + function Getc_Immed (File : File_Type) return int; + -- This routine is identical to Getc, except that the read is done in + -- Get_Immediate mode (i.e. without waiting for a line return). + + procedure Putc (ch : int; File : File_Type); + -- Outputs the given character to the file, which has already been checked + -- for being in output status. Device_Error is raised if the character + -- cannot be written. + procedure Set_WCEM (File : in out File_Type); -- Called by Open and Create to set the wide character encoding method for -- the file, processing a WCEM form parameter if one is present. File is -- IN OUT because it may be closed in case of an error. + procedure Terminate_Line (File : File_Type); + -- If the file is in Write_File or Append_File mode, and the current line + -- is not terminated, then a line terminator is written using New_Line. + -- Note that there is no Terminate_Page routine, because the page mark at + -- the end of the file is implied if necessary. + + procedure Ungetc (ch : int; File : File_Type); + -- Pushes back character into stream, using ungetc. The caller has checked + -- that the file is in read status. Device_Error is raised if the character + -- cannot be pushed back. An attempt to push back and end of file character + -- (EOF) is ignored. + ------------------- -- AFCB_Allocate -- ------------------- @@ -843,6 +879,52 @@ package body Ada.Wide_Text_IO is return ch; end Getc_Immed; + ------------------------------- + -- Initialize_Standard_Files -- + ------------------------------- + + procedure Initialize_Standard_Files is + begin + Standard_Err.Stream := stderr; + Standard_Err.Name := Err_Name'Access; + Standard_Err.Form := Null_Str'Unrestricted_Access; + Standard_Err.Mode := FCB.Out_File; + Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0; + Standard_Err.Is_Temporary_File := False; + Standard_Err.Is_System_File := True; + Standard_Err.Is_Text_File := True; + Standard_Err.Access_Method := 'T'; + Standard_Err.Self := Standard_Err; + Standard_Err.WC_Method := Default_WCEM; + + Standard_In.Stream := stdin; + Standard_In.Name := In_Name'Access; + Standard_In.Form := Null_Str'Unrestricted_Access; + Standard_In.Mode := FCB.In_File; + Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0; + Standard_In.Is_Temporary_File := False; + Standard_In.Is_System_File := True; + Standard_In.Is_Text_File := True; + Standard_In.Access_Method := 'T'; + Standard_In.Self := Standard_In; + Standard_In.WC_Method := Default_WCEM; + + Standard_Out.Stream := stdout; + Standard_Out.Name := Out_Name'Access; + Standard_Out.Form := Null_Str'Unrestricted_Access; + Standard_Out.Mode := FCB.Out_File; + Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0; + Standard_Out.Is_Temporary_File := False; + Standard_Out.Is_System_File := True; + Standard_Out.Is_Text_File := True; + Standard_Out.Access_Method := 'T'; + Standard_Out.Self := Standard_Out; + Standard_Out.WC_Method := Default_WCEM; + + FIO.Make_Unbuffered (AP (Standard_Out)); + FIO.Make_Unbuffered (AP (Standard_Err)); + end Initialize_Standard_Files; + ------------- -- Is_Open -- ------------- @@ -856,9 +938,9 @@ package body Ada.Wide_Text_IO is -- Line -- ---------- - -- Note: we assume that it is impossible in practice for the line - -- to exceed the value of Count'Last, i.e. no check is required for - -- overflow raising layout error. + -- Note: we assume that it is impossible in practice for the line to exceed + -- the value of Count'Last, i.e. no check is required for overflow raising + -- layout error. function Line (File : File_Type) return Positive_Count is begin @@ -1840,20 +1922,8 @@ package body Ada.Wide_Text_IO is set_text_mode (fileno (File.Stream)); end Write; - -- Use "preallocated" strings to avoid calling "new" during the - -- elaboration of the run time. This is needed in the tasking case to - -- avoid calling Task_Lock too early. A filename is expected to end with - -- a null character in the runtime, here the null characters are added - -- just to have a correct filename length. - - Err_Name : aliased String := "*stderr" & ASCII.NUL; - In_Name : aliased String := "*stdin" & ASCII.NUL; - Out_Name : aliased String := "*stdout" & ASCII.NUL; - begin - ------------------------------- - -- Initialize Standard Files -- - ------------------------------- + -- Initialize Standard Files for J in WC_Encoding_Method loop if WC_Encoding = WC_Encoding_Letters (J) then @@ -1861,51 +1931,10 @@ begin end if; end loop; - -- Note: the names in these files are bogus, and probably it would be - -- better for these files to have no names, but the ACVC test insist! - -- We use names that are bound to fail in open etc. - - Standard_Err.Stream := stderr; - Standard_Err.Name := Err_Name'Access; - Standard_Err.Form := Null_Str'Unrestricted_Access; - Standard_Err.Mode := FCB.Out_File; - Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0; - Standard_Err.Is_Temporary_File := False; - Standard_Err.Is_System_File := True; - Standard_Err.Is_Text_File := True; - Standard_Err.Access_Method := 'T'; - Standard_Err.Self := Standard_Err; - Standard_Err.WC_Method := Default_WCEM; - - Standard_In.Stream := stdin; - Standard_In.Name := In_Name'Access; - Standard_In.Form := Null_Str'Unrestricted_Access; - Standard_In.Mode := FCB.In_File; - Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0; - Standard_In.Is_Temporary_File := False; - Standard_In.Is_System_File := True; - Standard_In.Is_Text_File := True; - Standard_In.Access_Method := 'T'; - Standard_In.Self := Standard_In; - Standard_In.WC_Method := Default_WCEM; - - Standard_Out.Stream := stdout; - Standard_Out.Name := Out_Name'Access; - Standard_Out.Form := Null_Str'Unrestricted_Access; - Standard_Out.Mode := FCB.Out_File; - Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0; - Standard_Out.Is_Temporary_File := False; - Standard_Out.Is_System_File := True; - Standard_Out.Is_Text_File := True; - Standard_Out.Access_Method := 'T'; - Standard_Out.Self := Standard_Out; - Standard_Out.WC_Method := Default_WCEM; + Initialize_Standard_Files; FIO.Chain_File (AP (Standard_In)); FIO.Chain_File (AP (Standard_Out)); FIO.Chain_File (AP (Standard_Err)); - FIO.Make_Unbuffered (AP (Standard_Out)); - FIO.Make_Unbuffered (AP (Standard_Err)); - end Ada.Wide_Text_IO; diff --git a/gcc/ada/a-witeio.ads b/gcc/ada/a-witeio.ads index 0af805eb980..2cf02b69b05 100644 --- a/gcc/ada/a-witeio.ads +++ b/gcc/ada/a-witeio.ads @@ -42,6 +42,9 @@ with Ada.IO_Exceptions; with Ada.Streams; + +with Interfaces.C_Streams; + with System; with System.File_Control_Block; with System.WCh_Con; @@ -441,9 +444,6 @@ private -- The Standard Files -- ------------------------ - Null_Str : aliased constant String := ""; - -- Used as name and form of standard files - Standard_Err_AFCB : aliased Wide_Text_AFCB; Standard_In_AFCB : aliased Wide_Text_AFCB; Standard_Out_AFCB : aliased Wide_Text_AFCB; @@ -458,26 +458,24 @@ private Current_Err : aliased File_Type := Standard_Err; -- Current files + procedure Initialize_Standard_Files; + -- Initializes the file control blocks for the standard files. Called from + -- the elaboration routine for this package, and from Reset_Standard_Files + -- in package Ada.Wide_Text_IO.Reset_Standard_Files. + ----------------------- -- Local Subprograms -- ----------------------- -- These subprograms are in the private part of the spec so that they can - -- be shared by the routines in the body of Ada.Text_IO.Wide_Text_IO. - - -- Note: we use Integer in these declarations instead of the more accurate - -- Interfaces.C_Streams.int, because we do not want to drag in the spec of - -- this interfaces package with the spec of Ada.Text_IO, and we know that - -- in fact these types are identical + -- be shared by the children of Ada.Wide_Text_IO. - function Getc (File : File_Type) return Integer; - -- Gets next character from file, which has already been checked for - -- being in read status, and returns the character read if no error - -- occurs. The result is EOF if the end of file was read. + function Getc (File : File_Type) return Interfaces.C_Streams.int; + -- Gets next character from file, which has already been checked for being + -- in read status, and returns the character read if no error occurs. The + -- result is EOF if the end of file was read. - procedure Get_Character - (File : File_Type; - Item : out Character); + procedure Get_Character (File : File_Type; Item : out Character); -- This is essentially a copy of the normal Get routine from Text_IO. It -- obtains a single character from the input file File, and places it in -- Item. This character may be the leading character of a Wide_Character @@ -491,25 +489,8 @@ private -- read and is passed in C. The wide character value is returned as the -- result, and the file pointer is bumped past the character. - function Nextc (File : File_Type) return Integer; - -- Returns next character from file without skipping past it (i.e. it - -- is a combination of Getc followed by an Ungetc). - - procedure Putc (ch : Integer; File : File_Type); - -- Outputs the given character to the file, which has already been - -- checked for being in output status. Device_Error is raised if the - -- character cannot be written. - - procedure Terminate_Line (File : File_Type); - -- If the file is in Write_File or Append_File mode, and the current - -- line is not terminated, then a line terminator is written using - -- New_Line. Note that there is no Terminate_Page routine, because - -- the page mark at the end of the file is implied if necessary. - - procedure Ungetc (ch : Integer; File : File_Type); - -- Pushes back character into stream, using ungetc. The caller has - -- checked that the file is in read status. Device_Error is raised - -- if the character cannot be pushed back. An attempt to push back - -- and end of file character (EOF) is ignored. + function Nextc (File : File_Type) return Interfaces.C_Streams.int; + -- Returns next character from file without skipping past it (i.e. it is a + -- combination of Getc followed by an Ungetc). end Ada.Wide_Text_IO; diff --git a/gcc/ada/a-wrstfi.adb b/gcc/ada/a-wrstfi.adb new file mode 100644 index 00000000000..6b3f656b670 --- /dev/null +++ b/gcc/ada/a-wrstfi.adb @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- ADA.WIDE_TEXT_IO.RESET_STANDARD_FILES -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +------------------------------------------- +-- Ada.Wide_Text_IO.Reset_Standard_Files -- +------------------------------------------- + +procedure Ada.Wide_Text_IO.Reset_Standard_Files is +begin + Ada.Wide_Text_IO.Initialize_Standard_Files; +end Ada.Wide_Text_IO.Reset_Standard_Files; diff --git a/gcc/ada/a-wrstfi.ads b/gcc/ada/a-wrstfi.ads new file mode 100644 index 00000000000..5d6548eadc5 --- /dev/null +++ b/gcc/ada/a-wrstfi.ads @@ -0,0 +1,41 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- ADA.WIDE_TEXT_IO.RESET_STANDARD_FILES -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This package provides a reset routine that resets the standard files used +-- by Ada.Wide_Text_IO. This is useful in systems such as VxWorks where +-- Ada.Wide_Text_IO is elaborated at the program start, but a system restart +-- may alter the status of these files, resulting in incorrect operation of +-- Wide_Text_IO (in particular if the standard input file is changed to be +-- interactive, then Get_Line may hang looking for an extra character after +-- the end of the line. + +procedure Ada.Wide_Text_IO.Reset_Standard_Files; +-- Reset standard Wide_Text_IO files as described above diff --git a/gcc/ada/a-wtdeio.adb b/gcc/ada/a-wtdeio.adb index 8d42e85d54e..598b72a941e 100644 --- a/gcc/ada/a-wtdeio.adb +++ b/gcc/ada/a-wtdeio.adb @@ -54,16 +54,10 @@ package body Ada.Wide_Text_IO.Decimal_IO is is begin if Num'Size > Integer'Size then - Item := Num (Aux.Get_LLD (TFT (File), Width, Scale)); - -- Item := Num'Fixed_Value (Aux.Get_LLD (TFT (File), Width, Scale)); - -- above is what we should write, but gets assert error ??? - + Item := Num'Fixed_Value (Aux.Get_LLD (TFT (File), Width, Scale)); else - Item := Num (Aux.Get_Dec (TFT (File), Width, Scale)); - -- Item := Num'Fixed_Value (Aux.Get_Dec (TFT (File), Width, Scale)); - -- above is what we should write, but gets assert error ??? + Item := Num'Fixed_Value (Aux.Get_Dec (TFT (File), Width, Scale)); end if; - exception when Constraint_Error => raise Data_Error; end Get; diff --git a/gcc/ada/a-wtedit.adb b/gcc/ada/a-wtedit.adb index dbe09a9df15..cc41dc1cd86 100644 --- a/gcc/ada/a-wtedit.adb +++ b/gcc/ada/a-wtedit.adb @@ -477,21 +477,17 @@ package body Ada.Wide_Text_IO.Editing is raise Layout_Error; end if; - if Pic.Radix_Position = Invalid_Position then - Position := Answer'Last; - else - Position := Pic.Radix_Position - 1; - end if; + Position := + (if Pic.Radix_Position = Invalid_Position then Answer'Last + else Pic.Radix_Position - 1); for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop - while Answer (Position) /= '9' and then Answer (Position) /= Pic.Floater loop if Answer (Position) = '_' then Answer (Position) := Separator_Character; - elsif Answer (Position) = 'b' then Answer (Position) := ' '; end if; @@ -790,25 +786,22 @@ package body Ada.Wide_Text_IO.Editing is -- No trailing digits, but now J may need to stick in a currency -- symbol or sign. - if Pic.Start_Currency = Invalid_Position then - Position := Answer'Last + 1; - else - Position := Pic.Start_Currency; - end if; + Position := + (if Pic.Start_Currency = Invalid_Position then Answer'Last + 1 + else Pic.Start_Currency); end if; for J in Position .. Answer'Last loop - if Pic.Start_Currency /= Invalid_Position and then Answer (Pic.Start_Currency) = '#' then Currency_Pos := 1; end if; - -- Note: There are some weird cases J can imagine with 'b' or '#' - -- in currency strings where the following code will cause - -- glitches. The trick is to tell when the character in the - -- answer should be checked, and when to look at the original - -- string. Some other time. RIE 11/26/96 ??? + -- Note: There are some weird cases J can imagine with 'b' or '#' in + -- currency strings where the following code will cause glitches. The + -- trick is to tell when the character in the answer should be + -- checked, and when to look at the original string. Some other time. + -- RIE 11/26/96 ??? case Answer (J) is when '*' => @@ -942,8 +935,9 @@ package body Ada.Wide_Text_IO.Editing is -- 1) Expand $, replace '.' with Radix_Point - return Answer (1 .. Currency_Pos - 1) & Currency_Symbol & - Answer (Currency_Pos + 1 .. Answer'Last); + return + Answer (1 .. Currency_Pos - 1) & Currency_Symbol & + Answer (Currency_Pos + 1 .. Answer'Last); else -- 2) No currency expansion, replace '.' with Radix_Point diff --git a/gcc/ada/a-zrstfi.adb b/gcc/ada/a-zrstfi.adb new file mode 100755 index 00000000000..e0a7f64b662 --- /dev/null +++ b/gcc/ada/a-zrstfi.adb @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- ADA.WIDE_WIDE_TEXT_IO.RESET_STANDARD_FILES -- +-- -- +-- B o d y -- +-- -- +-- Copyright (C) 2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +------------------------------------------------ +-- Ada.Wide_Wide_Text_IO.Reset_Standard_Files -- +------------------------------------------------ + +procedure Ada.Wide_Wide_Text_IO.Reset_Standard_Files is +begin + Ada.Wide_Wide_Text_IO.Initialize_Standard_Files; +end Ada.Wide_Wide_Text_IO.Reset_Standard_Files; diff --git a/gcc/ada/a-zrstfi.ads b/gcc/ada/a-zrstfi.ads new file mode 100755 index 00000000000..80f2b1f2cdf --- /dev/null +++ b/gcc/ada/a-zrstfi.ads @@ -0,0 +1,41 @@ +------------------------------------------------------------------------------ +-- -- +-- GNAT RUN-TIME COMPONENTS -- +-- -- +-- ADA.WIDE_WIDE_TEXT_IO.RESET_STANDARD_FILES -- +-- -- +-- S p e c -- +-- -- +-- Copyright (C) 2009, Free Software Foundation, Inc. -- +-- -- +-- GNAT is free software; you can redistribute it and/or modify it under -- +-- terms of the GNU General Public License as published by the Free Soft- -- +-- ware Foundation; either version 3, or (at your option) any later ver- -- +-- sion. GNAT is distributed in the hope that it will be useful, but WITH- -- +-- OUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -- +-- or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- . -- +-- -- +-- GNAT was originally developed by the GNAT team at New York University. -- +-- Extensive contributions were provided by Ada Core Technologies Inc. -- +-- -- +------------------------------------------------------------------------------ + +-- This package provides a reset routine that resets the standard files used +-- by Ada.Wide_Wide_Text_IO. This is useful in systems such as VxWorks where +-- Ada.Wide_Wide_Text_IO is elaborated at the program start, but a system +-- restart may alter the status of these files, resulting in incorrect +-- operation of Wide_Wide_Text_IO (in particular if the standard input file +-- is changed to be interactive, then Get_Line may hang looking for an extra +-- character after the end of the line. + +procedure Ada.Wide_Wide_Text_IO.Reset_Standard_Files; +-- Reset standard Wide_Wide_Text_IO files as described above diff --git a/gcc/ada/a-ztdeau.adb b/gcc/ada/a-ztdeau.adb index b9feb4c1723..38450fcb011 100644 --- a/gcc/ada/a-ztdeau.adb +++ b/gcc/ada/a-ztdeau.adb @@ -244,11 +244,8 @@ package body Ada.Wide_Wide_Text_IO.Decimal_Aux is Ptr : Natural := 0; begin - if Exp = 0 then - Fore := To'Length - 1 - Aft; - else - Fore := To'Length - 2 - Aft - Exp; - end if; + Fore := + (if Exp = 0 then To'Length - 1 - Aft else To'Length - 2 - Aft - Exp); if Fore < 1 then raise Layout_Error; diff --git a/gcc/ada/a-ztdeio.adb b/gcc/ada/a-ztdeio.adb index cc61e8cbff9..52f8820a787 100644 --- a/gcc/ada/a-ztdeio.adb +++ b/gcc/ada/a-ztdeio.adb @@ -54,16 +54,10 @@ package body Ada.Wide_Wide_Text_IO.Decimal_IO is is begin if Num'Size > Integer'Size then - Item := Num (Aux.Get_LLD (TFT (File), Width, Scale)); - -- Item := Num'Fixed_Value (Aux.Get_LLD (TFT (File), Width, Scale)); - -- above is what we should write, but gets assert error ??? - + Item := Num'Fixed_Value (Aux.Get_LLD (TFT (File), Width, Scale)); else - Item := Num (Aux.Get_Dec (TFT (File), Width, Scale)); - -- Item := Num'Fixed_Value (Aux.Get_Dec (TFT (File), Width, Scale)); - -- above is what we should write, but gets assert error ??? + Item := Num'Fixed_Value (Aux.Get_Dec (TFT (File), Width, Scale)); end if; - exception when Constraint_Error => raise Data_Error; end Get; diff --git a/gcc/ada/a-ztedit.adb b/gcc/ada/a-ztedit.adb index 555e66491ef..9b5036a4d08 100644 --- a/gcc/ada/a-ztedit.adb +++ b/gcc/ada/a-ztedit.adb @@ -478,21 +478,17 @@ package body Ada.Wide_Wide_Text_IO.Editing is raise Layout_Error; end if; - if Pic.Radix_Position = Invalid_Position then - Position := Answer'Last; - else - Position := Pic.Radix_Position - 1; - end if; + Position := + (if Pic.Radix_Position = Invalid_Position then Answer'Last + else Pic.Radix_Position - 1); for J in reverse Attrs.Start_Of_Int .. Attrs.End_Of_Int loop - while Answer (Position) /= '9' and then Answer (Position) /= Pic.Floater loop if Answer (Position) = '_' then Answer (Position) := Separator_Character; - elsif Answer (Position) = 'b' then Answer (Position) := ' '; end if; @@ -791,15 +787,12 @@ package body Ada.Wide_Wide_Text_IO.Editing is -- No trailing digits, but now J may need to stick in a currency -- symbol or sign. - if Pic.Start_Currency = Invalid_Position then - Position := Answer'Last + 1; - else - Position := Pic.Start_Currency; - end if; + Position := + (if Pic.Start_Currency = Invalid_Position then Answer'Last + 1 + else Pic.Start_Currency); end if; for J in Position .. Answer'Last loop - if Pic.Start_Currency /= Invalid_Position and then Answer (Pic.Start_Currency) = '#' then Currency_Pos := 1; diff --git a/gcc/ada/a-ztexio.adb b/gcc/ada/a-ztexio.adb index 64ad87215db..8be8a91d9e2 100644 --- a/gcc/ada/a-ztexio.adb +++ b/gcc/ada/a-ztexio.adb @@ -57,26 +57,62 @@ package body Ada.Wide_Wide_Text_IO is WC_Encoding : Character; pragma Import (C, WC_Encoding, "__gl_wc_encoding"); + -- Default wide character encoding + + Err_Name : aliased String := "*stderr" & ASCII.NUL; + In_Name : aliased String := "*stdin" & ASCII.NUL; + Out_Name : aliased String := "*stdout" & ASCII.NUL; + -- Names of standard files + -- + -- Use "preallocated" strings to avoid calling "new" during the elaboration + -- of the run time. This is needed in the tasking case to avoid calling + -- Task_Lock too early. A filename is expected to end with a null character + -- in the runtime, here the null characters are added just to have a + -- correct filename length. + -- + -- Note: the names for these files are bogus, and probably it would be + -- better for these files to have no names, but the ACVC tests insist! + -- We use names that are bound to fail in open etc. + + Null_Str : aliased constant String := ""; + -- Used as form string for standard files ----------------------- -- Local Subprograms -- ----------------------- - function Getc_Immed (File : File_Type) return int; - -- This routine is identical to Getc, except that the read is done in - -- Get_Immediate mode (i.e. without waiting for a line return). - function Get_Wide_Wide_Char_Immed (C : Character; File : File_Type) return Wide_Wide_Character; -- This routine is identical to Get_Wide_Wide_Char, except that the reads -- are done in Get_Immediate mode (i.e. without waiting for a line return). + function Getc_Immed (File : File_Type) return int; + -- This routine is identical to Getc, except that the read is done in + -- Get_Immediate mode (i.e. without waiting for a line return). + + procedure Putc (ch : int; File : File_Type); + -- Outputs the given character to the file, which has already been checked + -- for being in output status. Device_Error is raised if the character + -- cannot be written. + procedure Set_WCEM (File : in out File_Type); -- Called by Open and Create to set the wide character encoding method for -- the file, processing a WCEM form parameter if one is present. File is -- IN OUT because it may be closed in case of an error. + procedure Terminate_Line (File : File_Type); + -- If the file is in Write_File or Append_File mode, and the current line + -- is not terminated, then a line terminator is written using New_Line. + -- Note that there is no Terminate_Page routine, because the page mark at + -- the end of the file is implied if necessary. + + procedure Ungetc (ch : int; File : File_Type); + -- Pushes back character into stream, using ungetc. The caller has checked + -- that the file is in read status. Device_Error is raised if the character + -- cannot be pushed back. An attempt to push back and end of file character + -- (EOF) is ignored. + ------------------- -- AFCB_Allocate -- ------------------- @@ -843,6 +879,52 @@ package body Ada.Wide_Wide_Text_IO is return ch; end Getc_Immed; + ------------------------------- + -- Initialize_Standard_Files -- + ------------------------------- + + procedure Initialize_Standard_Files is + begin + Standard_Err.Stream := stderr; + Standard_Err.Name := Err_Name'Access; + Standard_Err.Form := Null_Str'Unrestricted_Access; + Standard_Err.Mode := FCB.Out_File; + Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0; + Standard_Err.Is_Temporary_File := False; + Standard_Err.Is_System_File := True; + Standard_Err.Is_Text_File := True; + Standard_Err.Access_Method := 'T'; + Standard_Err.Self := Standard_Err; + Standard_Err.WC_Method := Default_WCEM; + + Standard_In.Stream := stdin; + Standard_In.Name := In_Name'Access; + Standard_In.Form := Null_Str'Unrestricted_Access; + Standard_In.Mode := FCB.In_File; + Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0; + Standard_In.Is_Temporary_File := False; + Standard_In.Is_System_File := True; + Standard_In.Is_Text_File := True; + Standard_In.Access_Method := 'T'; + Standard_In.Self := Standard_In; + Standard_In.WC_Method := Default_WCEM; + + Standard_Out.Stream := stdout; + Standard_Out.Name := Out_Name'Access; + Standard_Out.Form := Null_Str'Unrestricted_Access; + Standard_Out.Mode := FCB.Out_File; + Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0; + Standard_Out.Is_Temporary_File := False; + Standard_Out.Is_System_File := True; + Standard_Out.Is_Text_File := True; + Standard_Out.Access_Method := 'T'; + Standard_Out.Self := Standard_Out; + Standard_Out.WC_Method := Default_WCEM; + + FIO.Make_Unbuffered (AP (Standard_Out)); + FIO.Make_Unbuffered (AP (Standard_Err)); + end Initialize_Standard_Files; + ------------- -- Is_Open -- ------------- @@ -1840,20 +1922,8 @@ package body Ada.Wide_Wide_Text_IO is set_text_mode (fileno (File.Stream)); end Write; - -- Use "preallocated" strings to avoid calling "new" during the - -- elaboration of the run time. This is needed in the tasking case to - -- avoid calling Task_Lock too early. A filename is expected to end with - -- a null character in the runtime, here the null characters are added - -- just to have a correct filename length. - - Err_Name : aliased String := "*stderr" & ASCII.NUL; - In_Name : aliased String := "*stdin" & ASCII.NUL; - Out_Name : aliased String := "*stdout" & ASCII.NUL; - begin - ------------------------------- - -- Initialize Standard Files -- - ------------------------------- + -- Initialize Standard Files for J in WC_Encoding_Method loop if WC_Encoding = WC_Encoding_Letters (J) then @@ -1861,51 +1931,10 @@ begin end if; end loop; - -- Note: the names in these files are bogus, and probably it would be - -- better for these files to have no names, but the ACVC test insist! - -- We use names that are bound to fail in open etc. - - Standard_Err.Stream := stderr; - Standard_Err.Name := Err_Name'Access; - Standard_Err.Form := Null_Str'Unrestricted_Access; - Standard_Err.Mode := FCB.Out_File; - Standard_Err.Is_Regular_File := is_regular_file (fileno (stderr)) /= 0; - Standard_Err.Is_Temporary_File := False; - Standard_Err.Is_System_File := True; - Standard_Err.Is_Text_File := True; - Standard_Err.Access_Method := 'T'; - Standard_Err.Self := Standard_Err; - Standard_Err.WC_Method := Default_WCEM; - - Standard_In.Stream := stdin; - Standard_In.Name := In_Name'Access; - Standard_In.Form := Null_Str'Unrestricted_Access; - Standard_In.Mode := FCB.In_File; - Standard_In.Is_Regular_File := is_regular_file (fileno (stdin)) /= 0; - Standard_In.Is_Temporary_File := False; - Standard_In.Is_System_File := True; - Standard_In.Is_Text_File := True; - Standard_In.Access_Method := 'T'; - Standard_In.Self := Standard_In; - Standard_In.WC_Method := Default_WCEM; - - Standard_Out.Stream := stdout; - Standard_Out.Name := Out_Name'Access; - Standard_Out.Form := Null_Str'Unrestricted_Access; - Standard_Out.Mode := FCB.Out_File; - Standard_Out.Is_Regular_File := is_regular_file (fileno (stdout)) /= 0; - Standard_Out.Is_Temporary_File := False; - Standard_Out.Is_System_File := True; - Standard_Out.Is_Text_File := True; - Standard_Out.Access_Method := 'T'; - Standard_Out.Self := Standard_Out; - Standard_Out.WC_Method := Default_WCEM; + Initialize_Standard_Files; FIO.Chain_File (AP (Standard_In)); FIO.Chain_File (AP (Standard_Out)); FIO.Chain_File (AP (Standard_Err)); - FIO.Make_Unbuffered (AP (Standard_Out)); - FIO.Make_Unbuffered (AP (Standard_Err)); - end Ada.Wide_Wide_Text_IO; diff --git a/gcc/ada/a-ztexio.ads b/gcc/ada/a-ztexio.ads index 81ab9924775..6c75acd1936 100644 --- a/gcc/ada/a-ztexio.ads +++ b/gcc/ada/a-ztexio.ads @@ -42,6 +42,9 @@ with Ada.IO_Exceptions; with Ada.Streams; + +with Interfaces.C_Streams; + with System; with System.File_Control_Block; with System.WCh_Con; @@ -357,13 +360,13 @@ private PM : constant := Character'Pos (ASCII.FF); -- Used as page mark, except at end of file where it is implied - ------------------------------------- + ------------------------------------------ -- Wide_Wide_Text_IO File Control Block -- - ------------------------------------- + ------------------------------------------ Default_WCEM : WCh_Con.WC_Encoding_Method := WCh_Con.WCEM_UTF8; - -- This gets modified during initialization (see body) using - -- the default value established in the call to Set_Globals. + -- This gets modified during initialization (see body) using the default + -- value established in the call to Set_Globals. package FCB renames System.File_Control_Block; @@ -443,9 +446,6 @@ private -- The Standard Files -- ------------------------ - Null_Str : aliased constant String := ""; - -- Used as name and form of standard files - Standard_Err_AFCB : aliased Wide_Wide_Text_AFCB; Standard_In_AFCB : aliased Wide_Wide_Text_AFCB; Standard_Out_AFCB : aliased Wide_Wide_Text_AFCB; @@ -460,31 +460,28 @@ private Current_Err : aliased File_Type := Standard_Err; -- Current files + procedure Initialize_Standard_Files; + -- Initializes the file control blocks for the standard files. Called from + -- the elaboration routine for this package, and from Reset_Standard_Files + -- in package Ada.Wide_Wide_Text_IO.Reset_Standard_Files. + ----------------------- -- Local Subprograms -- ----------------------- -- These subprograms are in the private part of the spec so that they can - -- be shared by the routines in the body of Ada.Text_IO.Wide_Wide_Text_IO. - - -- Note: we use Integer in these declarations instead of the more accurate - -- Interfaces.C_Streams.int, because we do not want to drag in the spec of - -- this interfaces package with the spec of Ada.Text_IO, and we know that - -- in fact these types are identical + -- be shared by the children of Ada.Text_IO.Wide_Wide_Text_IO. - function Getc (File : File_Type) return Integer; - -- Gets next character from file, which has already been checked for - -- being in read status, and returns the character read if no error - -- occurs. The result is EOF if the end of file was read. + function Getc (File : File_Type) return Interfaces.C_Streams.int; + -- Gets next character from file, which has already been checked for being + -- in read status, and returns the character read if no error occurs. The + -- result is EOF if the end of file was read. - procedure Get_Character - (File : File_Type; - Item : out Character); - -- This is essentially a copy of the normal Get routine from Text_IO. It + procedure Get_Character (File : File_Type; Item : out Character); + -- This is essentially copy of Wide_Wide_Text_IO.Get. It obtains a single -- obtains a single character from the input file File, and places it in - -- Item. This character may be the leading character of a - -- Wide_Wide_Character sequence, but that is up to the caller to deal - -- with. + -- Item. This result may be the leading character of a Wide_Wide_Character + -- sequence, but that is up to the caller to deal with. function Get_Wide_Wide_Char (C : Character; @@ -494,25 +491,8 @@ private -- read and is passed in C. The wide character value is returned as the -- result, and the file pointer is bumped past the character. - function Nextc (File : File_Type) return Integer; - -- Returns next character from file without skipping past it (i.e. it - -- is a combination of Getc followed by an Ungetc). - - procedure Putc (ch : Integer; File : File_Type); - -- Outputs the given character to the file, which has already been - -- checked for being in output status. Device_Error is raised if the - -- character cannot be written. - - procedure Terminate_Line (File : File_Type); - -- If the file is in Write_File or Append_File mode, and the current - -- line is not terminated, then a line terminator is written using - -- New_Line. Note that there is no Terminate_Page routine, because - -- the page mark at the end of the file is implied if necessary. - - procedure Ungetc (ch : Integer; File : File_Type); - -- Pushes back character into stream, using ungetc. The caller has - -- checked that the file is in read status. Device_Error is raised - -- if the character cannot be pushed back. An attempt to push back - -- and end of file character (EOF) is ignored. + function Nextc (File : File_Type) return Interfaces.C_Streams.int; + -- Returns next character from file without skipping past it (i.e. it is a + -- combination of Getc followed by an Ungetc). end Ada.Wide_Wide_Text_IO; diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c index c3405daaf44..5bce387d2bb 100644 --- a/gcc/ada/adaint.c +++ b/gcc/ada/adaint.c @@ -324,6 +324,12 @@ const int __gnat_vmsp = 0; #endif +/* Used for Ada bindings */ +const int __gnat_size_of_file_attributes = sizeof (struct file_attributes); + +/* Reset the file attributes as if no system call had been performed */ +void __gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr); + /* The __gnat_max_path_len variable is used to export the maximum length of a path name to Ada code. max_path_len is also provided for compatibility with older GNAT versions, please do not use @@ -371,6 +377,24 @@ to_ptr32 (char **ptr64) #define MAYBE_TO_PTR32(argv) argv #endif +void +__gnat_reset_attributes + (struct file_attributes* attr) +{ + attr->exists = -1; + + attr->writable = -1; + attr->readable = -1; + attr->executable = -1; + + attr->regular = -1; + attr->symbolic_link = -1; + attr->directory = -1; + + attr->timestamp = (OS_Time)-2; + attr->file_length = -1; +} + OS_Time __gnat_current_time (void) @@ -922,6 +946,28 @@ __gnat_create_output_file (char *path) return fd < 0 ? -1 : fd; } +int +__gnat_create_output_file_new (char *path) +{ + int fd; +#if defined (VMS) + fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM, + "rfm=stmlf", "ctx=rec", "rat=none", "rop=nlk", + "shr=del,get,put,upd"); +#elif defined (__MINGW32__) + { + TCHAR wpath[GNAT_MAX_PATH_LEN]; + + S2WSC (wpath, path, GNAT_MAX_PATH_LEN); + fd = _topen (wpath, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM); + } +#else + fd = open (path, O_WRONLY | O_CREAT | O_TRUNC | O_TEXT | O_EXCL, PERM); +#endif + + return fd < 0 ? -1 : fd; +} + int __gnat_open_append (char *path, int fmode) { @@ -1014,42 +1060,89 @@ __gnat_open_new_temp (char *path, int fmode) return fd < 0 ? -1 : fd; } -/* Return the number of bytes in the specified file. */ +/**************************************************************** + ** Perform a call to GNAT_STAT or GNAT_FSTAT, and extract as much information + ** as possible from it, storing the result in a cache for later reuse + ****************************************************************/ -long -__gnat_file_length (int fd) +void +__gnat_stat_to_attr (int fd, char* name, struct file_attributes* attr) { - int ret; GNAT_STRUCT_STAT statbuf; + int ret; - ret = GNAT_FSTAT (fd, &statbuf); - if (ret || !S_ISREG (statbuf.st_mode)) - return 0; + if (fd != -1) + ret = GNAT_FSTAT (fd, &statbuf); + else + ret = __gnat_stat (name, &statbuf); + + attr->regular = (!ret && S_ISREG (statbuf.st_mode)); + attr->directory = (!ret && S_ISDIR (statbuf.st_mode)); + + if (!attr->regular) + attr->file_length = 0; + else + /* st_size may be 32 bits, or 64 bits which is converted to long. We + don't return a useful value for files larger than 2 gigabytes in + either case. */ + attr->file_length = statbuf.st_size; /* all systems */ + +#ifndef __MINGW32__ + /* on Windows requires extra system call, see comment in __gnat_file_exists_attr */ + attr->exists = !ret; +#endif - /* st_size may be 32 bits, or 64 bits which is converted to long. We - don't return a useful value for files larger than 2 gigabytes in - either case. */ +#if !defined (_WIN32) || defined (RTX) + /* on Windows requires extra system call, see __gnat_is_readable_file_attr */ + attr->readable = (!ret && (statbuf.st_mode & S_IRUSR)); + attr->writable = (!ret && (statbuf.st_mode & S_IWUSR)); + attr->executable = (!ret && (statbuf.st_mode & S_IXUSR)); +#endif + +#if !defined (__EMX__) && !defined (MSDOS) && (!defined (_WIN32) || defined (RTX)) + /* on Windows requires extra system call, see __gnat_file_time_name_attr */ + if (ret != 0) { + attr->timestamp = (OS_Time)-1; + } else { +#ifdef VMS + /* VMS has file versioning. */ + attr->timestamp = (OS_Time)statbuf.st_ctime; +#else + attr->timestamp = (OS_Time)statbuf.st_mtime; +#endif + } +#endif - return (statbuf.st_size); } -/* Return the number of bytes in the specified named file. */ +/**************************************************************** + ** Return the number of bytes in the specified file + ****************************************************************/ long -__gnat_named_file_length (char *name) +__gnat_file_length_attr (int fd, char* name, struct file_attributes* attr) { - int ret; - GNAT_STRUCT_STAT statbuf; + if (attr->file_length == -1) { + __gnat_stat_to_attr (fd, name, attr); + } - ret = __gnat_stat (name, &statbuf); - if (ret || !S_ISREG (statbuf.st_mode)) - return 0; + return attr->file_length; +} - /* st_size may be 32 bits, or 64 bits which is converted to long. We - don't return a useful value for files larger than 2 gigabytes in - either case. */ +long +__gnat_file_length (int fd) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_file_length_attr (fd, NULL, &attr); +} - return (statbuf.st_size); +long +__gnat_named_file_length (char *name) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_file_length_attr (-1, name, &attr); } /* Create a temporary filename and put it in string pointed to by @@ -1244,137 +1337,136 @@ win32_filetime (HANDLE h) /* Return a GNAT time stamp given a file name. */ OS_Time -__gnat_file_time_name (char *name) +__gnat_file_time_name_attr (char* name, struct file_attributes* attr) { - + if (attr->timestamp == (OS_Time)-2) { #if defined (__EMX__) || defined (MSDOS) - int fd = open (name, O_RDONLY | O_BINARY); - time_t ret = __gnat_file_time_fd (fd); - close (fd); - return (OS_Time)ret; + int fd = open (name, O_RDONLY | O_BINARY); + time_t ret = __gnat_file_time_fd (fd); + close (fd); + attr->timestamp = (OS_Time)ret; #elif defined (_WIN32) && !defined (RTX) - time_t ret = -1; - TCHAR wname[GNAT_MAX_PATH_LEN]; - - S2WSC (wname, name, GNAT_MAX_PATH_LEN); + time_t ret = -1; + TCHAR wname[GNAT_MAX_PATH_LEN]; + S2WSC (wname, name, GNAT_MAX_PATH_LEN); - HANDLE h = CreateFile - (wname, GENERIC_READ, FILE_SHARE_READ, 0, - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); + HANDLE h = CreateFile + (wname, GENERIC_READ, FILE_SHARE_READ, 0, + OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); - if (h != INVALID_HANDLE_VALUE) - { - ret = win32_filetime (h); - CloseHandle (h); - } - return (OS_Time) ret; -#else - GNAT_STRUCT_STAT statbuf; - if (__gnat_stat (name, &statbuf) != 0) { - return (OS_Time)-1; - } else { -#ifdef VMS - /* VMS has file versioning. */ - return (OS_Time)statbuf.st_ctime; + if (h != INVALID_HANDLE_VALUE) { + ret = win32_filetime (h); + CloseHandle (h); + } + attr->timestamp = (OS_Time) ret; #else - return (OS_Time)statbuf.st_mtime; + __gnat_stat_to_attr (-1, name, attr); #endif } -#endif + return attr->timestamp; +} + +OS_Time +__gnat_file_time_name (char *name) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_file_time_name_attr (name, &attr); } /* Return a GNAT time stamp given a file descriptor. */ OS_Time -__gnat_file_time_fd (int fd) +__gnat_file_time_fd_attr (int fd, struct file_attributes* attr) { - /* The following workaround code is due to the fact that under EMX and - DJGPP fstat attempts to convert time values to GMT rather than keep the - actual OS timestamp of the file. By using the OS2/DOS functions directly - the GNAT timestamp are independent of this behavior, which is desired to - facilitate the distribution of GNAT compiled libraries. */ + if (attr->timestamp == (OS_Time)-2) { + /* The following workaround code is due to the fact that under EMX and + DJGPP fstat attempts to convert time values to GMT rather than keep the + actual OS timestamp of the file. By using the OS2/DOS functions directly + the GNAT timestamp are independent of this behavior, which is desired to + facilitate the distribution of GNAT compiled libraries. */ #if defined (__EMX__) || defined (MSDOS) #ifdef __EMX__ - FILESTATUS fs; - int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs, - sizeof (FILESTATUS)); + FILESTATUS fs; + int ret = DosQueryFileInfo (fd, 1, (unsigned char *) &fs, + sizeof (FILESTATUS)); - unsigned file_year = fs.fdateLastWrite.year; - unsigned file_month = fs.fdateLastWrite.month; - unsigned file_day = fs.fdateLastWrite.day; - unsigned file_hour = fs.ftimeLastWrite.hours; - unsigned file_min = fs.ftimeLastWrite.minutes; - unsigned file_tsec = fs.ftimeLastWrite.twosecs; + unsigned file_year = fs.fdateLastWrite.year; + unsigned file_month = fs.fdateLastWrite.month; + unsigned file_day = fs.fdateLastWrite.day; + unsigned file_hour = fs.ftimeLastWrite.hours; + unsigned file_min = fs.ftimeLastWrite.minutes; + unsigned file_tsec = fs.ftimeLastWrite.twosecs; #else - struct ftime fs; - int ret = getftime (fd, &fs); + struct ftime fs; + int ret = getftime (fd, &fs); - unsigned file_year = fs.ft_year; - unsigned file_month = fs.ft_month; - unsigned file_day = fs.ft_day; - unsigned file_hour = fs.ft_hour; - unsigned file_min = fs.ft_min; - unsigned file_tsec = fs.ft_tsec; + unsigned file_year = fs.ft_year; + unsigned file_month = fs.ft_month; + unsigned file_day = fs.ft_day; + unsigned file_hour = fs.ft_hour; + unsigned file_min = fs.ft_min; + unsigned file_tsec = fs.ft_tsec; #endif - /* Calculate the seconds since epoch from the time components. First count - the whole days passed. The value for years returned by the DOS and OS2 - functions count years from 1980, so to compensate for the UNIX epoch which - begins in 1970 start with 10 years worth of days and add days for each - four year period since then. */ + /* Calculate the seconds since epoch from the time components. First count + the whole days passed. The value for years returned by the DOS and OS2 + functions count years from 1980, so to compensate for the UNIX epoch which + begins in 1970 start with 10 years worth of days and add days for each + four year period since then. */ - time_t tot_secs; - int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; - int days_passed = 3652 + (file_year / 4) * 1461; - int years_since_leap = file_year % 4; + time_t tot_secs; + int cum_days[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + int days_passed = 3652 + (file_year / 4) * 1461; + int years_since_leap = file_year % 4; - if (years_since_leap == 1) - days_passed += 366; - else if (years_since_leap == 2) - days_passed += 731; - else if (years_since_leap == 3) - days_passed += 1096; + if (years_since_leap == 1) + days_passed += 366; + else if (years_since_leap == 2) + days_passed += 731; + else if (years_since_leap == 3) + days_passed += 1096; - if (file_year > 20) - days_passed -= 1; + if (file_year > 20) + days_passed -= 1; - days_passed += cum_days[file_month - 1]; - if (years_since_leap == 0 && file_year != 20 && file_month > 2) - days_passed++; + days_passed += cum_days[file_month - 1]; + if (years_since_leap == 0 && file_year != 20 && file_month > 2) + days_passed++; - days_passed += file_day - 1; + days_passed += file_day - 1; - /* OK - have whole days. Multiply -- then add in other parts. */ + /* OK - have whole days. Multiply -- then add in other parts. */ - tot_secs = days_passed * 86400; - tot_secs += file_hour * 3600; - tot_secs += file_min * 60; - tot_secs += file_tsec * 2; - return (OS_Time) tot_secs; + tot_secs = days_passed * 86400; + tot_secs += file_hour * 3600; + tot_secs += file_min * 60; + tot_secs += file_tsec * 2; + attr->timestamp = (OS_Time) tot_secs; #elif defined (_WIN32) && !defined (RTX) - HANDLE h = (HANDLE) _get_osfhandle (fd); - time_t ret = win32_filetime (h); - return (OS_Time) ret; + HANDLE h = (HANDLE) _get_osfhandle (fd); + time_t ret = win32_filetime (h); + attr->timestamp = (OS_Time) ret; #else - GNAT_STRUCT_STAT statbuf; - - if (GNAT_FSTAT (fd, &statbuf) != 0) { - return (OS_Time) -1; - } else { -#ifdef VMS - /* VMS has file versioning. */ - return (OS_Time) statbuf.st_ctime; -#else - return (OS_Time) statbuf.st_mtime; -#endif - } + __gnat_stat_to_attr (fd, NULL, attr); #endif + } + + return attr->timestamp; +} + +OS_Time +__gnat_file_time_fd (int fd) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_file_time_fd_attr (fd, &attr); } /* Set the file time stamp. */ @@ -1700,24 +1792,41 @@ __gnat_stat (char *name, GNAT_STRUCT_STAT *statbuf) #endif } +/************************************************************************* + ** Check whether a file exists + *************************************************************************/ + int -__gnat_file_exists (char *name) +__gnat_file_exists_attr (char* name, struct file_attributes* attr) { + if (attr->exists == -1) { #ifdef __MINGW32__ - /* On Windows do not use __gnat_stat() because a bug in Microsoft - _stat() routine. When the system time-zone is set with a negative - offset the _stat() routine fails on specific files like CON: */ - TCHAR wname [GNAT_MAX_PATH_LEN + 2]; - - S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); - return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES; + /* On Windows do not use __gnat_stat() because of a bug in Microsoft + _stat() routine. When the system time-zone is set with a negative + offset the _stat() routine fails on specific files like CON: */ + TCHAR wname [GNAT_MAX_PATH_LEN + 2]; + S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); + attr->exists = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES; #else - GNAT_STRUCT_STAT statbuf; - - return !__gnat_stat (name, &statbuf); + __gnat_stat_to_attr (-1, name, attr); #endif + } + + return attr->exists; +} + +int +__gnat_file_exists (char *name) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_file_exists_attr (name, &attr); } +/********************************************************************** + ** Whether name is an absolute path + **********************************************************************/ + int __gnat_is_absolute_path (char *name, int length) { @@ -1753,24 +1862,40 @@ __gnat_is_absolute_path (char *name, int length) #endif } +int +__gnat_is_regular_file_attr (char* name, struct file_attributes* attr) +{ + if (attr->regular == -1) { + __gnat_stat_to_attr (-1, name, attr); + } + + return attr->regular; +} + int __gnat_is_regular_file (char *name) { - int ret; - GNAT_STRUCT_STAT statbuf; + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_is_regular_file_attr (name, &attr); +} - ret = __gnat_stat (name, &statbuf); - return (!ret && S_ISREG (statbuf.st_mode)); +int +__gnat_is_directory_attr (char* name, struct file_attributes* attr) +{ + if (attr->directory == -1) { + __gnat_stat_to_attr (-1, name, attr); + } + + return attr->directory; } int __gnat_is_directory (char *name) { - int ret; - GNAT_STRUCT_STAT statbuf; - - ret = __gnat_stat (name, &statbuf); - return (!ret && S_ISDIR (statbuf.st_mode)); + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_is_directory_attr (name, &attr); } #if defined (_WIN32) && !defined (RTX) @@ -1964,95 +2089,111 @@ __gnat_can_use_acl (TCHAR *wname) #endif /* defined (_WIN32) && !defined (RTX) */ int -__gnat_is_readable_file (char *name) +__gnat_is_readable_file_attr (char* name, struct file_attributes* attr) { + if (attr->readable == -1) { #if defined (_WIN32) && !defined (RTX) - TCHAR wname [GNAT_MAX_PATH_LEN + 2]; - GENERIC_MAPPING GenericMapping; - - S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); - - if (__gnat_can_use_acl (wname)) - { - ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING)); - GenericMapping.GenericRead = GENERIC_READ; + TCHAR wname [GNAT_MAX_PATH_LEN + 2]; + GENERIC_MAPPING GenericMapping; - return __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping); - } - else - return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES; + S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); + if (__gnat_can_use_acl (wname)) + { + ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING)); + GenericMapping.GenericRead = GENERIC_READ; + attr->readable = __gnat_check_OWNER_ACL (wname, FILE_READ_DATA, GenericMapping); + } + else + attr->readable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES; #else - int ret; - int mode; - GNAT_STRUCT_STAT statbuf; - - ret = GNAT_STAT (name, &statbuf); - mode = statbuf.st_mode & S_IRUSR; - return (!ret && mode); + __gnat_stat_to_attr (-1, name, attr); #endif + } + + return attr->readable; } int -__gnat_is_writable_file (char *name) +__gnat_is_readable_file (char *name) { + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_is_readable_file_attr (name, &attr); +} + +int +__gnat_is_writable_file_attr (char* name, struct file_attributes* attr) +{ + if (attr->writable == -1) { #if defined (_WIN32) && !defined (RTX) - TCHAR wname [GNAT_MAX_PATH_LEN + 2]; - GENERIC_MAPPING GenericMapping; + TCHAR wname [GNAT_MAX_PATH_LEN + 2]; + GENERIC_MAPPING GenericMapping; - S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); + S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); - if (__gnat_can_use_acl (wname)) - { - ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING)); - GenericMapping.GenericWrite = GENERIC_WRITE; + if (__gnat_can_use_acl (wname)) + { + ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING)); + GenericMapping.GenericWrite = GENERIC_WRITE; - return __gnat_check_OWNER_ACL - (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping) - && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY); - } - else - return !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY); + attr->writable = __gnat_check_OWNER_ACL + (wname, FILE_WRITE_DATA | FILE_APPEND_DATA, GenericMapping) + && !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY); + } + else + attr->writable = !(GetFileAttributes (wname) & FILE_ATTRIBUTE_READONLY); #else - int ret; - int mode; - GNAT_STRUCT_STAT statbuf; - - ret = GNAT_STAT (name, &statbuf); - mode = statbuf.st_mode & S_IWUSR; - return (!ret && mode); + __gnat_stat_to_attr (-1, name, attr); #endif + } + + return attr->writable; } int -__gnat_is_executable_file (char *name) +__gnat_is_writable_file (char *name) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_is_writable_file_attr (name, &attr); +} + +int +__gnat_is_executable_file_attr (char* name, struct file_attributes* attr) { + if (attr->executable == -1) { #if defined (_WIN32) && !defined (RTX) - TCHAR wname [GNAT_MAX_PATH_LEN + 2]; - GENERIC_MAPPING GenericMapping; + TCHAR wname [GNAT_MAX_PATH_LEN + 2]; + GENERIC_MAPPING GenericMapping; - S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); + S2WSC (wname, name, GNAT_MAX_PATH_LEN + 2); - if (__gnat_can_use_acl (wname)) - { - ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING)); - GenericMapping.GenericExecute = GENERIC_EXECUTE; + if (__gnat_can_use_acl (wname)) + { + ZeroMemory (&GenericMapping, sizeof (GENERIC_MAPPING)); + GenericMapping.GenericExecute = GENERIC_EXECUTE; - return __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping); - } - else - return GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES - && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4); + attr->executable = __gnat_check_OWNER_ACL (wname, FILE_EXECUTE, GenericMapping); + } + else + attr->executable = GetFileAttributes (wname) != INVALID_FILE_ATTRIBUTES + && _tcsstr (wname, _T(".exe")) - wname == (int) (_tcslen (wname) - 4); #else - int ret; - int mode; - GNAT_STRUCT_STAT statbuf; - - ret = GNAT_STAT (name, &statbuf); - mode = statbuf.st_mode & S_IXUSR; - return (!ret && mode); + __gnat_stat_to_attr (-1, name, attr); #endif + } + + return attr->executable; +} + +int +__gnat_is_executable_file (char *name) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_is_executable_file_attr (name, &attr); } void @@ -2171,21 +2312,31 @@ __gnat_set_non_readable (char *name) } int -__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED) +__gnat_is_symbolic_link_attr (char* name, struct file_attributes* attr) { + if (attr->symbolic_link == -1) { #if defined (__vxworks) || defined (__nucleus__) - return 0; + attr->symbolic_link = 0; #elif defined (_AIX) || defined (__APPLE__) || defined (__unix__) - int ret; - GNAT_STRUCT_STAT statbuf; - - ret = GNAT_LSTAT (name, &statbuf); - return (!ret && S_ISLNK (statbuf.st_mode)); - + int ret; + GNAT_STRUCT_STAT statbuf; + ret = GNAT_LSTAT (name, &statbuf); + attr->symbolic_link = (!ret && S_ISLNK (statbuf.st_mode)); #else - return 0; + attr->symbolic_link = 0; #endif + } + return attr->symbolic_link; +} + +int +__gnat_is_symbolic_link (char *name ATTRIBUTE_UNUSED) +{ + struct file_attributes attr; + __gnat_reset_attributes (&attr); + return __gnat_is_symbolic_link_attr (name, &attr); + } #if defined (sun) && defined (__SVR4) diff --git a/gcc/ada/adaint.h b/gcc/ada/adaint.h index 79a1e4eb4bd..76a181a001c 100644 --- a/gcc/ada/adaint.h +++ b/gcc/ada/adaint.h @@ -68,6 +68,30 @@ typedef long long OS_Time; typedef long OS_Time; #endif +/* A lazy cache for the attributes of a file. On some systems, a single call to + stat() will give all this information, so it is better than doing a system + call every time. On other systems this require several system calls. +*/ + +struct file_attributes { + short exists; + + short writable; + short readable; + short executable; + + short symbolic_link; + short regular; + short directory; + + OS_Time timestamp; + long file_length; +}; +/* WARNING: changing the size here might require changing the constant + * File_Attributes_Size in osint.ads (which should be big enough to + * fit the above struct on any system) + */ + extern int __gnat_max_path_len; extern OS_Time __gnat_current_time (void); extern void __gnat_current_time_string (char *); @@ -121,15 +145,28 @@ extern OS_Time __gnat_file_time_fd (int); extern void __gnat_set_file_time_name (char *, time_t); -extern int __gnat_dup (int); -extern int __gnat_dup2 (int, int); -extern int __gnat_file_exists (char *); -extern int __gnat_is_regular_file (char *); -extern int __gnat_is_absolute_path (char *,int); -extern int __gnat_is_directory (char *); +extern int __gnat_dup (int); +extern int __gnat_dup2 (int, int); +extern int __gnat_file_exists (char *); +extern int __gnat_is_regular_file (char *); +extern int __gnat_is_absolute_path (char *,int); +extern int __gnat_is_directory (char *); extern int __gnat_is_writable_file (char *); extern int __gnat_is_readable_file (char *name); -extern int __gnat_is_executable_file (char *name); +extern int __gnat_is_executable_file (char *name); + +extern void __gnat_reset_attributes (struct file_attributes* attr); +extern long __gnat_file_length_attr (int, char *, struct file_attributes *); +extern OS_Time __gnat_file_time_name_attr (char *, struct file_attributes *); +extern OS_Time __gnat_file_time_fd_attr (int, struct file_attributes *); +extern int __gnat_file_exists_attr (char *, struct file_attributes *); +extern int __gnat_is_regular_file_attr (char *, struct file_attributes *); +extern int __gnat_is_directory_attr (char *, struct file_attributes *); +extern int __gnat_is_readable_file_attr (char *, struct file_attributes *); +extern int __gnat_is_writable_file_attr (char *, struct file_attributes *); +extern int __gnat_is_executable_file_attr (char *, struct file_attributes *); +extern int __gnat_is_symbolic_link_attr (char *, struct file_attributes *); + extern void __gnat_set_non_writable (char *name); extern void __gnat_set_writable (char *name); extern void __gnat_set_executable (char *name); diff --git a/gcc/ada/ali.adb b/gcc/ada/ali.adb index b2357eae970..20438cf66e6 100644 --- a/gcc/ada/ali.adb +++ b/gcc/ada/ali.adb @@ -190,7 +190,7 @@ package body ALI is function Get_Name (Ignore_Spaces : Boolean := False; - Ignore_Special : Boolean := False)return Name_Id; + Ignore_Special : Boolean := False) return Name_Id; -- Skip blanks, then scan out a name (name is left in Name_Buffer with -- length in Name_Len, as well as being returned in Name_Id form). -- If Lower is set to True then the Name_Buffer will be converted to diff --git a/gcc/ada/bcheck.adb b/gcc/ada/bcheck.adb index 8119a6d7a43..18739e878ed 100644 --- a/gcc/ada/bcheck.adb +++ b/gcc/ada/bcheck.adb @@ -190,7 +190,7 @@ package body Bcheck is else ALI_Path_Id := - Osint.Find_File ((ALIs.Table (A).Afile), Osint.Library); + Osint.Full_Lib_File_Name (ALIs.Table (A).Afile); if Osint.Is_Readonly_Library (ALI_Path_Id) then if Tolerate_Consistency_Errors then Error_Msg ("?{ should be recompiled"); diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb index d1a2b460c90..ff511665b73 100644 --- a/gcc/ada/checks.adb +++ b/gcc/ada/checks.adb @@ -28,6 +28,7 @@ with Debug; use Debug; with Einfo; use Einfo; with Errout; use Errout; with Exp_Ch2; use Exp_Ch2; +with Exp_Ch4; use Exp_Ch4; with Exp_Ch11; use Exp_Ch11; with Exp_Pakd; use Exp_Pakd; with Exp_Util; use Exp_Util; @@ -844,7 +845,10 @@ package body Checks is begin -- Skip check if back end does overflow checks, or the overflow flag - -- is not set anyway, or we are not doing code expansion. + -- is not set anyway, or we are not doing code expansion, or the + -- parent node is a type conversion whose operand is an arithmetic + -- operation on signed integers on which the expander can promote + -- later the operands to type Integer (see Expand_N_Type_Conversion). -- Special case CLI target, where arithmetic overflow checks can be -- performed for integer and long_integer @@ -852,6 +856,9 @@ package body Checks is if Backend_Overflow_Checks_On_Target or else not Do_Overflow_Check (N) or else not Expander_Active + or else (Present (Parent (N)) + and then Nkind (Parent (N)) = N_Type_Conversion + and then Integer_Promotion_Possible (Parent (N))) or else (VM_Target = CLI_Target and then Siz >= Standard_Integer_Size) then diff --git a/gcc/ada/env.c b/gcc/ada/env.c index ac6e835df9f..d9486977433 100644 --- a/gcc/ada/env.c +++ b/gcc/ada/env.c @@ -29,8 +29,11 @@ * * ****************************************************************************/ -/* Tru64 UNIX declares unsetenv() only if _BSD. */ +/* Tru64 UNIX V4.0F declares unsetenv() only if AES_SOURCE (which + is plain broken, this should be _AES_SOURCE instead as everywhere else; + Tru64 UNIX V5.1B declares it only if _BSD. */ #if defined (__alpha__) && defined (__osf__) +#define AES_SOURCE #define _BSD #endif diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb index 913e46df374..0e29af2c64e 100644 --- a/gcc/ada/exp_aggr.adb +++ b/gcc/ada/exp_aggr.adb @@ -509,7 +509,7 @@ package body Exp_Aggr is -- 10. No controlled actions need to be generated for components - -- 11. The backend is a No_VM backend and the array has aliased components + -- 11. For a VM back end, the array should have no aliased components function Backend_Processing_Possible (N : Node_Id) return Boolean is Typ : constant Entity_Id := Etype (N); @@ -3298,8 +3298,14 @@ package body Exp_Aggr is N_Discriminant_Specification then Flist := Empty; - else + + elsif Needs_Finalization (Typ) then Flist := Find_Final_List (Access_Type); + + -- Otherwise there are no controlled actions to be performed. + + else + Flist := Empty; end if; if Is_Array_Type (Typ) then diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb index d5cce9b43ee..48bd566b38b 100644 --- a/gcc/ada/exp_attr.adb +++ b/gcc/ada/exp_attr.adb @@ -654,10 +654,18 @@ package body Exp_Attr is Make_Build_In_Place_Call_In_Anonymous_Context (Pref); end if; - -- If prefix is a protected type name, this is a reference to - -- the current instance of the type. - - if Is_Protected_Self_Reference (Pref) then + -- If prefix is a protected type name, this is a reference to the + -- current instance of the type. For a component definition, nothing + -- to do (expansion will occur in the init proc). In other contexts, + -- rewrite into reference to current instance. + + if Is_Protected_Self_Reference (Pref) + and then not + (Nkind_In (Parent (N), N_Index_Or_Discriminant_Constraint, + N_Discriminant_Association) + and then Nkind (Parent (Parent (Parent (Parent (N))))) = + N_Component_Definition) + then Rewrite (Pref, Concurrent_Ref (Pref)); Analyze (Pref); end if; @@ -680,9 +688,9 @@ package body Exp_Attr is function Enclosing_Object (N : Node_Id) return Node_Id; -- If N denotes a compound name (selected component, indexed - -- component, or slice), returns the name of the outermost - -- such enclosing object. Otherwise returns N. If the object - -- is a renaming, then the renamed object is returned. + -- component, or slice), returns the name of the outermost such + -- enclosing object. Otherwise returns N. If the object is a + -- renaming, then the renamed object is returned. ---------------------- -- Enclosing_Object -- diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index 414e5670115..9a91e2aa9bb 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -2733,70 +2733,11 @@ package body Exp_Ch3 is Next_Non_Pragma (Decl); end loop; - if Per_Object_Constraint_Components then - - -- Second pass: components with per-object constraints - - Decl := First_Non_Pragma (Component_Items (Comp_List)); - while Present (Decl) loop - Loc := Sloc (Decl); - Id := Defining_Identifier (Decl); - Typ := Etype (Id); - - if Has_Access_Constraint (Id) - and then No (Expression (Decl)) - then - if Has_Non_Null_Base_Init_Proc (Typ) then - Append_List_To (Statement_List, - Build_Initialization_Call (Loc, - Make_Selected_Component (Loc, - Prefix => Make_Identifier (Loc, Name_uInit), - Selector_Name => New_Occurrence_Of (Id, Loc)), - Typ, - In_Init_Proc => True, - Enclos_Type => Rec_Type, - Discr_Map => Discr_Map)); - - Clean_Task_Names (Typ, Proc_Id); - - elsif Component_Needs_Simple_Initialization (Typ) then - Append_List_To (Statement_List, - Build_Assignment - (Id, Get_Simple_Init_Val (Typ, N, Esize (Id)))); - end if; - end if; - - Next_Non_Pragma (Decl); - end loop; - end if; - - -- Process the variant part - - if Present (Variant_Part (Comp_List)) then - Alt_List := New_List; - Variant := First_Non_Pragma (Variants (Variant_Part (Comp_List))); - while Present (Variant) loop - Loc := Sloc (Variant); - Append_To (Alt_List, - Make_Case_Statement_Alternative (Loc, - Discrete_Choices => - New_Copy_List (Discrete_Choices (Variant)), - Statements => - Build_Init_Statements (Component_List (Variant)))); - Next_Non_Pragma (Variant); - end loop; - - -- The expression of the case statement which is a reference - -- to one of the discriminants is replaced by the appropriate - -- formal parameter of the initialization procedure. - - Append_To (Statement_List, - Make_Case_Statement (Loc, - Expression => - New_Reference_To (Discriminal ( - Entity (Name (Variant_Part (Comp_List)))), Loc), - Alternatives => Alt_List)); - end if; + -- Set up tasks and protected object support. This needs to be done + -- before any component with a per-object access discriminant + -- constraint, or any variant part (which may contain such + -- components) is initialized, because the initialization of these + -- components may reference the enclosing concurrent object. -- For a task record type, add the task create call and calls -- to bind any interrupt (signal) entries. @@ -2898,6 +2839,71 @@ package body Exp_Ch3 is end if; end if; + if Per_Object_Constraint_Components then + + -- Second pass: components with per-object constraints + + Decl := First_Non_Pragma (Component_Items (Comp_List)); + while Present (Decl) loop + Loc := Sloc (Decl); + Id := Defining_Identifier (Decl); + Typ := Etype (Id); + + if Has_Access_Constraint (Id) + and then No (Expression (Decl)) + then + if Has_Non_Null_Base_Init_Proc (Typ) then + Append_List_To (Statement_List, + Build_Initialization_Call (Loc, + Make_Selected_Component (Loc, + Prefix => Make_Identifier (Loc, Name_uInit), + Selector_Name => New_Occurrence_Of (Id, Loc)), + Typ, + In_Init_Proc => True, + Enclos_Type => Rec_Type, + Discr_Map => Discr_Map)); + + Clean_Task_Names (Typ, Proc_Id); + + elsif Component_Needs_Simple_Initialization (Typ) then + Append_List_To (Statement_List, + Build_Assignment + (Id, Get_Simple_Init_Val (Typ, N, Esize (Id)))); + end if; + end if; + + Next_Non_Pragma (Decl); + end loop; + end if; + + -- Process the variant part + + if Present (Variant_Part (Comp_List)) then + Alt_List := New_List; + Variant := First_Non_Pragma (Variants (Variant_Part (Comp_List))); + while Present (Variant) loop + Loc := Sloc (Variant); + Append_To (Alt_List, + Make_Case_Statement_Alternative (Loc, + Discrete_Choices => + New_Copy_List (Discrete_Choices (Variant)), + Statements => + Build_Init_Statements (Component_List (Variant)))); + Next_Non_Pragma (Variant); + end loop; + + -- The expression of the case statement which is a reference + -- to one of the discriminants is replaced by the appropriate + -- formal parameter of the initialization procedure. + + Append_To (Statement_List, + Make_Case_Statement (Loc, + Expression => + New_Reference_To (Discriminal ( + Entity (Name (Variant_Part (Comp_List)))), Loc), + Alternatives => Alt_List)); + end if; + -- If no initializations when generated for component declarations -- corresponding to this Statement_List, append a null statement -- to the Statement_List to make it a valid Ada tree. diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb index 6a65e10a167..6a7ea4fdb1b 100644 --- a/gcc/ada/exp_ch4.adb +++ b/gcc/ada/exp_ch4.adb @@ -8042,88 +8042,41 @@ package body Exp_Ch4 is -- have to be sure not to generate junk overflow checks in the first -- place, since it would be trick to remove them here! - declare - Root_Operand_Type : constant Entity_Id := Root_Type (Operand_Type); - - begin - -- Enable transformation if all conditions are met - - if - -- We only do this transformation for source constructs. We assume - -- that the expander knows what it is doing when it generates code. + if Integer_Promotion_Possible (N) then - Comes_From_Source (N) + -- All conditions met, go ahead with transformation - -- If the operand type is Short_Integer or Short_Short_Integer, - -- then we will promote to Integer, which is available on all - -- targets, and is sufficient to ensure no intermediate overflow. - -- Furthermore it is likely to be as efficient or more efficient - -- than using the smaller type for the computation so we do this - -- unconditionally. - - and then - (Root_Operand_Type = Base_Type (Standard_Short_Integer) - or else - Root_Operand_Type = Base_Type (Standard_Short_Short_Integer)) - - -- Test for interesting operation, which includes addition, - -- division, exponentiation, multiplication, subtraction, and - -- unary negation. + declare + Opnd : Node_Id; + L, R : Node_Id; - and then Nkind_In (Operand, N_Op_Add, - N_Op_Divide, - N_Op_Expon, - N_Op_Minus, - N_Op_Multiply, - N_Op_Subtract) - then - -- All conditions met, go ahead with transformation + begin + R := + Make_Type_Conversion (Loc, + Subtype_Mark => New_Reference_To (Standard_Integer, Loc), + Expression => Relocate_Node (Right_Opnd (Operand))); - declare - Opnd : Node_Id; - L, R : Node_Id; + Opnd := New_Op_Node (Nkind (Operand), Loc); + Set_Right_Opnd (Opnd, R); - begin - R := + if Nkind (Operand) in N_Binary_Op then + L := Make_Type_Conversion (Loc, Subtype_Mark => New_Reference_To (Standard_Integer, Loc), - Expression => Relocate_Node (Right_Opnd (Operand))); - - if Nkind (Operand) = N_Op_Minus then - Opnd := Make_Op_Minus (Loc, Right_Opnd => R); + Expression => Relocate_Node (Left_Opnd (Operand))); - else - L := - Make_Type_Conversion (Loc, - Subtype_Mark => New_Reference_To (Standard_Integer, Loc), - Expression => Relocate_Node (Left_Opnd (Operand))); - - case Nkind (Operand) is - when N_Op_Add => - Opnd := Make_Op_Add (Loc, L, R); - when N_Op_Divide => - Opnd := Make_Op_Divide (Loc, L, R); - when N_Op_Expon => - Opnd := Make_Op_Expon (Loc, L, R); - when N_Op_Multiply => - Opnd := Make_Op_Multiply (Loc, L, R); - when N_Op_Subtract => - Opnd := Make_Op_Subtract (Loc, L, R); - when others => - raise Program_Error; - end case; + Set_Left_Opnd (Opnd, L); + end if; - Rewrite (N, - Make_Type_Conversion (Loc, - Subtype_Mark => Relocate_Node (Subtype_Mark (N)), - Expression => Opnd)); + Rewrite (N, + Make_Type_Conversion (Loc, + Subtype_Mark => Relocate_Node (Subtype_Mark (N)), + Expression => Opnd)); - Analyze_And_Resolve (N, Target_Type); - return; - end if; - end; - end if; - end; + Analyze_And_Resolve (N, Target_Type); + return; + end; + end if; -- Do validity check if validity checking operands @@ -9187,6 +9140,51 @@ package body Exp_Ch4 is return; end Insert_Dereference_Action; + -------------------------------- + -- Integer_Promotion_Possible -- + -------------------------------- + + function Integer_Promotion_Possible (N : Node_Id) return Boolean is + Operand : constant Node_Id := Expression (N); + Operand_Type : constant Entity_Id := Etype (Operand); + Root_Operand_Type : constant Entity_Id := Root_Type (Operand_Type); + + begin + pragma Assert (Nkind (N) = N_Type_Conversion); + + return + + -- We only do the transformation for source constructs. We assume + -- that the expander knows what it is doing when it generates code. + + Comes_From_Source (N) + + -- If the operand type is Short_Integer or Short_Short_Integer, + -- then we will promote to Integer, which is available on all + -- targets, and is sufficient to ensure no intermediate overflow. + -- Furthermore it is likely to be as efficient or more efficient + -- than using the smaller type for the computation so we do this + -- unconditionally. + + and then + (Root_Operand_Type = Base_Type (Standard_Short_Integer) + or else + Root_Operand_Type = Base_Type (Standard_Short_Short_Integer)) + + -- Test for interesting operation, which includes addition, + -- division, exponentiation, multiplication, subtraction, absolute + -- value and unary negation. Unary "+" is omitted since it is a + -- no-op and thus can't overflow. + + and then Nkind_In (Operand, N_Op_Abs, + N_Op_Add, + N_Op_Divide, + N_Op_Expon, + N_Op_Minus, + N_Op_Multiply, + N_Op_Subtract); + end Integer_Promotion_Possible; + ------------------------------ -- Make_Array_Comparison_Op -- ------------------------------ diff --git a/gcc/ada/exp_ch4.ads b/gcc/ada/exp_ch4.ads index d1ed208f1b3..fad8c15eea1 100644 --- a/gcc/ada/exp_ch4.ads +++ b/gcc/ada/exp_ch4.ads @@ -6,7 +6,7 @@ -- -- -- S p e c -- -- -- --- Copyright (C) 1992-2008, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2009, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -88,4 +88,11 @@ package Exp_Ch4 is -- to insert those bodies at the right place. Nod provides the Sloc -- value for generated code. + function Integer_Promotion_Possible (N : Node_Id) return Boolean; + -- Returns true if the node is a type conversion whose operand is an + -- arithmetic operation on signed integers, and the base type of the + -- signed integer type is smaller than Standard.Integer. In such case we + -- have special circuitry in Expand_N_Type_Conversion to promote both of + -- the operands to type Integer. + end Exp_Ch4; diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb index db22726bb64..7fe20b37cad 100644 --- a/gcc/ada/exp_ch9.adb +++ b/gcc/ada/exp_ch9.adb @@ -3983,9 +3983,21 @@ package body Exp_Ch9 is Spec_Id : Entity_Id; begin - Spec_Id := - Make_Defining_Identifier (Loc, - Chars => New_External_Name (Chars (T), 'B')); + -- Case of explicit task type, suffix TB + + if Comes_From_Source (T) then + Spec_Id := + Make_Defining_Identifier (Loc, + Chars => New_External_Name (Chars (T), "TB")); + + -- Case of anonymous task type, suffix B + + else + Spec_Id := + Make_Defining_Identifier (Loc, + Chars => New_External_Name (Chars (T), 'B')); + end if; + Set_Is_Internal (Spec_Id); -- Associate the procedure with the task, if this is the declaration @@ -7821,20 +7833,23 @@ package body Exp_Ch9 is declare Old_Comp : constant Node_Id := Component_Definition (Priv); - Pent : constant Entity_Id := Defining_Identifier (Priv); + Oent : constant Entity_Id := Defining_Identifier (Priv); New_Comp : Node_Id; + Nent : constant Entity_Id := + Make_Defining_Identifier (Sloc (Oent), + Chars => Chars (Oent)); begin if Present (Subtype_Indication (Old_Comp)) then New_Comp := - Make_Component_Definition (Sloc (Pent), + Make_Component_Definition (Sloc (Oent), Aliased_Present => False, Subtype_Indication => New_Copy_Tree (Subtype_Indication (Old_Comp), Discr_Map)); else New_Comp := - Make_Component_Definition (Sloc (Pent), + Make_Component_Definition (Sloc (Oent), Aliased_Present => False, Access_Definition => New_Copy_Tree (Access_Definition (Old_Comp), @@ -7843,10 +7858,12 @@ package body Exp_Ch9 is New_Priv := Make_Component_Declaration (Loc, - Defining_Identifier => - Make_Defining_Identifier (Sloc (Pent), Chars (Pent)), + Defining_Identifier => Nent, Component_Definition => New_Comp, - Expression => Expression (Priv)); + Expression => Expression (Priv)); + + Set_Has_Per_Object_Constraint (Nent, + Has_Per_Object_Constraint (Oent)); Append_To (Cdecls, New_Priv); end; diff --git a/gcc/ada/exp_ch9.ads b/gcc/ada/exp_ch9.ads index 8e795e12c0f..61279d4eac5 100644 --- a/gcc/ada/exp_ch9.ads +++ b/gcc/ada/exp_ch9.ads @@ -173,8 +173,8 @@ package Exp_Ch9 is -- meaning is to get the Task_Id for the currently executing task. function Convert_Concurrent - (N : Node_Id; - Typ : Entity_Id) return Node_Id; + (N : Node_Id; + Typ : Entity_Id) return Node_Id; -- N is an expression of type Typ. If the type is not a concurrent type -- then it is returned unchanged. If it is a task or protected reference, -- Convert_Concurrent creates an unchecked conversion node from this diff --git a/gcc/ada/exp_dbug.ads b/gcc/ada/exp_dbug.ads index 3c3144641d8..1d26bb3ef75 100644 --- a/gcc/ada/exp_dbug.ads +++ b/gcc/ada/exp_dbug.ads @@ -873,12 +873,12 @@ package Exp_Dbug is -- the element type for AT1 might have a type defined as if it had -- been written: -- - -- type at1___C_PAD is record null; end record; - -- for at1___C_PAD'Size use 16 * 8; + -- type at1___PAD is record null; end record; + -- for at1___PAD'Size use 16 * 8; -- -- and there would also be -- - -- type at1___C_PAD___XVS is record t1: Integer; end record; + -- type at1___PAD___XVS is record t1: Integer; end record; -- type t1 is ... -- -- Had the subtype Int been dynamic: @@ -888,7 +888,7 @@ package Exp_Dbug is -- Then the compiler would also generate a declaration whose effect -- would be -- - -- at1___C_PAD___XVZ: constant Integer := 32 + M * 8 + padding term; + -- at1___PAD___XVZ: constant Integer := 32 + M * 8 + padding term; -- -- Not all unconstrained types are so encoded; the XVS convention may be -- unnecessary for unconstrained types of fixed size. However, this diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in index 163274c4332..02887029b22 100644 --- a/gcc/ada/gcc-interface/Make-lang.in +++ b/gcc/ada/gcc-interface/Make-lang.in @@ -1295,29 +1295,30 @@ ada/checks.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/casing.ads ada/checks.ads ada/checks.adb ada/csets.ads \ ada/debug.ads ada/einfo.ads ada/einfo.adb ada/elists.ads ada/elists.adb \ ada/err_vars.ads ada/errout.ads ada/erroutc.ads ada/eval_fat.ads \ - ada/exp_aggr.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch6.ads \ - ada/exp_ch7.ads ada/exp_dist.ads ada/exp_pakd.ads ada/exp_tss.ads \ - ada/exp_util.ads ada/exp_util.adb ada/fname.ads ada/fname-uf.ads \ - ada/freeze.ads ada/get_targ.ads ada/gnat.ads ada/g-hesorg.ads \ - ada/g-htable.ads ada/hostparm.ads ada/inline.ads ada/itypes.ads \ - ada/lib.ads ada/lib.adb ada/lib-list.adb ada/lib-load.ads \ - ada/lib-sort.adb ada/namet.ads ada/nlists.ads ada/nlists.adb \ - ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads ada/restrict.ads \ - ada/restrict.adb ada/rident.ads ada/rtsfind.ads ada/rtsfind.adb \ - ada/sem.ads ada/sem_aux.ads ada/sem_cat.ads ada/sem_ch3.ads \ - ada/sem_ch6.ads ada/sem_ch7.ads ada/sem_ch8.ads ada/sem_dist.ads \ - ada/sem_eval.ads ada/sem_eval.adb ada/sem_res.ads ada/sem_scil.ads \ - ada/sem_type.ads ada/sem_util.ads ada/sem_warn.ads ada/sinfo.ads \ - ada/sinfo.adb ada/sinput.ads ada/snames.ads ada/sprint.ads \ - ada/stand.ads ada/stringt.ads ada/stringt.adb ada/system.ads \ - ada/s-exctab.ads ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads \ - ada/s-os_lib.ads ada/s-parame.ads ada/s-rident.ads ada/s-soflin.ads \ - ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb \ - ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads ada/s-wchcon.ads \ - ada/table.ads ada/table.adb ada/targparm.ads ada/tbuild.ads \ - ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads ada/types.ads \ - ada/uintp.ads ada/uintp.adb ada/uname.ads ada/unchconv.ads \ - ada/unchdeal.ads ada/urealp.ads ada/urealp.adb ada/validsw.ads + ada/exp_aggr.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch4.ads \ + ada/exp_ch6.ads ada/exp_ch7.ads ada/exp_dist.ads ada/exp_pakd.ads \ + ada/exp_tss.ads ada/exp_util.ads ada/exp_util.adb ada/fname.ads \ + ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ + ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads ada/inline.ads \ + ada/itypes.ads ada/lib.ads ada/lib.adb ada/lib-list.adb \ + ada/lib-load.ads ada/lib-sort.adb ada/namet.ads ada/nlists.ads \ + ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads \ + ada/restrict.ads ada/restrict.adb ada/rident.ads ada/rtsfind.ads \ + ada/rtsfind.adb ada/sem.ads ada/sem_aux.ads ada/sem_cat.ads \ + ada/sem_ch3.ads ada/sem_ch6.ads ada/sem_ch7.ads ada/sem_ch8.ads \ + ada/sem_dist.ads ada/sem_eval.ads ada/sem_eval.adb ada/sem_res.ads \ + ada/sem_scil.ads ada/sem_type.ads ada/sem_util.ads ada/sem_warn.ads \ + ada/sinfo.ads ada/sinfo.adb ada/sinput.ads ada/snames.ads \ + ada/sprint.ads ada/stand.ads ada/stringt.ads ada/stringt.adb \ + ada/system.ads ada/s-exctab.ads ada/s-htable.ads ada/s-imenne.ads \ + ada/s-memory.ads ada/s-os_lib.ads ada/s-parame.ads ada/s-rident.ads \ + ada/s-soflin.ads ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads \ + ada/s-stoele.adb ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads \ + ada/s-wchcon.ads ada/table.ads ada/table.adb ada/targparm.ads \ + ada/tbuild.ads ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads \ + ada/types.ads ada/uintp.ads ada/uintp.adb ada/uname.ads \ + ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads ada/urealp.adb \ + ada/validsw.ads ada/comperr.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/a-uncdea.ads ada/alloc.ads ada/atree.ads ada/atree.adb \ @@ -1467,12 +1468,12 @@ ada/exp_aggr.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/debug.ads ada/einfo.ads ada/einfo.adb ada/elists.ads ada/elists.adb \ ada/err_vars.ads ada/errout.ads ada/erroutc.ads ada/eval_fat.ads \ ada/exp_aggr.ads ada/exp_aggr.adb ada/exp_ch11.ads ada/exp_ch2.ads \ - ada/exp_ch3.ads ada/exp_ch6.ads ada/exp_ch7.ads ada/exp_ch9.ads \ - ada/exp_disp.ads ada/exp_dist.ads ada/exp_pakd.ads ada/exp_tss.ads \ - ada/exp_util.ads ada/exp_util.adb ada/expander.ads ada/fname.ads \ - ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ - ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads ada/inline.ads \ - ada/interfac.ads ada/itypes.ads ada/lib.ads ada/lib.adb \ + ada/exp_ch3.ads ada/exp_ch4.ads ada/exp_ch6.ads ada/exp_ch7.ads \ + ada/exp_ch9.ads ada/exp_disp.ads ada/exp_dist.ads ada/exp_pakd.ads \ + ada/exp_tss.ads ada/exp_util.ads ada/exp_util.adb ada/expander.ads \ + ada/fname.ads ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads \ + ada/gnat.ads ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads \ + ada/inline.ads ada/interfac.ads ada/itypes.ads ada/lib.ads ada/lib.adb \ ada/lib-list.adb ada/lib-load.ads ada/lib-sort.adb ada/lib-xref.ads \ ada/namet.ads ada/namet.adb ada/nlists.ads ada/nlists.adb ada/nmake.ads \ ada/nmake.adb ada/opt.ads ada/output.ads ada/restrict.ads \ @@ -1691,31 +1692,32 @@ ada/exp_ch5.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/debug.ads ada/einfo.ads ada/einfo.adb ada/elists.ads ada/elists.adb \ ada/err_vars.ads ada/errout.ads ada/erroutc.ads ada/eval_fat.ads \ ada/exp_aggr.ads ada/exp_atag.ads ada/exp_ch11.ads ada/exp_ch2.ads \ - ada/exp_ch5.ads ada/exp_ch5.adb ada/exp_ch6.ads ada/exp_ch7.ads \ - ada/exp_dbug.ads ada/exp_disp.ads ada/exp_pakd.ads ada/exp_tss.ads \ - ada/exp_util.ads ada/exp_util.adb ada/fname.ads ada/fname-uf.ads \ - ada/freeze.ads ada/get_targ.ads ada/gnat.ads ada/g-htable.ads \ - ada/hostparm.ads ada/inline.ads ada/interfac.ads ada/itypes.ads \ - ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb ada/nlists.ads \ - ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads \ - ada/restrict.ads ada/restrict.adb ada/rident.ads ada/rtsfind.ads \ - ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb ada/sem.ads \ - ada/sem_attr.ads ada/sem_aux.ads ada/sem_cat.ads ada/sem_ch13.ads \ - ada/sem_ch3.ads ada/sem_ch6.ads ada/sem_ch8.ads ada/sem_disp.ads \ - ada/sem_eval.ads ada/sem_eval.adb ada/sem_res.ads ada/sem_scil.ads \ - ada/sem_type.ads ada/sem_util.ads ada/sem_util.adb ada/sem_warn.ads \ - ada/sinfo.ads ada/sinfo.adb ada/sinput.ads ada/snames.ads \ - ada/sprint.ads ada/stand.ads ada/stringt.ads ada/stringt.adb \ - ada/style.ads ada/styleg.ads ada/styleg.adb ada/stylesw.ads \ - ada/system.ads ada/s-crc32.ads ada/s-exctab.ads ada/s-htable.ads \ - ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads ada/s-parame.ads \ - ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads ada/s-stache.ads \ - ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb ada/s-string.ads \ - ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads ada/s-wchcon.ads \ - ada/table.ads ada/table.adb ada/targparm.ads ada/tbuild.ads \ - ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads ada/types.ads \ - ada/uintp.ads ada/uintp.adb ada/uname.ads ada/unchconv.ads \ - ada/unchdeal.ads ada/urealp.ads ada/validsw.ads ada/widechar.ads + ada/exp_ch4.ads ada/exp_ch5.ads ada/exp_ch5.adb ada/exp_ch6.ads \ + ada/exp_ch7.ads ada/exp_dbug.ads ada/exp_disp.ads ada/exp_pakd.ads \ + ada/exp_tss.ads ada/exp_util.ads ada/exp_util.adb ada/fname.ads \ + ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ + ada/g-htable.ads ada/hostparm.ads ada/inline.ads ada/interfac.ads \ + ada/itypes.ads ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb \ + ada/nlists.ads ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads \ + ada/output.ads ada/restrict.ads ada/restrict.adb ada/rident.ads \ + ada/rtsfind.ads ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb \ + ada/sem.ads ada/sem_attr.ads ada/sem_aux.ads ada/sem_cat.ads \ + ada/sem_ch13.ads ada/sem_ch3.ads ada/sem_ch6.ads ada/sem_ch8.ads \ + ada/sem_disp.ads ada/sem_eval.ads ada/sem_eval.adb ada/sem_res.ads \ + ada/sem_scil.ads ada/sem_type.ads ada/sem_util.ads ada/sem_util.adb \ + ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb ada/sinput.ads \ + ada/snames.ads ada/sprint.ads ada/stand.ads ada/stringt.ads \ + ada/stringt.adb ada/style.ads ada/styleg.ads ada/styleg.adb \ + ada/stylesw.ads ada/system.ads ada/s-crc32.ads ada/s-exctab.ads \ + ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads \ + ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads \ + ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb \ + ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads \ + ada/s-wchcon.ads ada/table.ads ada/table.adb ada/targparm.ads \ + ada/tbuild.ads ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads \ + ada/types.ads ada/uintp.ads ada/uintp.adb ada/uname.ads \ + ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads ada/validsw.ads \ + ada/widechar.ads ada/exp_ch6.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/a-uncdea.ads ada/alloc.ads ada/atree.ads ada/atree.adb \ @@ -1723,34 +1725,35 @@ ada/exp_ch6.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/debug.ads ada/einfo.ads ada/einfo.adb ada/elists.ads ada/elists.adb \ ada/err_vars.ads ada/errout.ads ada/erroutc.ads ada/eval_fat.ads \ ada/exp_aggr.ads ada/exp_atag.ads ada/exp_ch11.ads ada/exp_ch2.ads \ - ada/exp_ch3.ads ada/exp_ch6.ads ada/exp_ch6.adb ada/exp_ch7.ads \ - ada/exp_ch9.ads ada/exp_dbug.ads ada/exp_disp.ads ada/exp_dist.ads \ - ada/exp_intr.ads ada/exp_pakd.ads ada/exp_tss.ads ada/exp_util.ads \ - ada/exp_util.adb ada/exp_vfpt.ads ada/fname.ads ada/fname-uf.ads \ - ada/freeze.ads ada/get_targ.ads ada/gnat.ads ada/g-hesorg.ads \ - ada/g-htable.ads ada/hostparm.ads ada/inline.ads ada/interfac.ads \ - ada/itypes.ads ada/lib.ads ada/lib.adb ada/lib-list.adb \ - ada/lib-load.ads ada/lib-sort.adb ada/lib-xref.ads ada/namet.ads \ - ada/namet.adb ada/nlists.ads ada/nlists.adb ada/nmake.ads ada/nmake.adb \ - ada/opt.ads ada/output.ads ada/restrict.ads ada/restrict.adb \ - ada/rident.ads ada/rtsfind.ads ada/rtsfind.adb ada/scans.ads \ - ada/scn.ads ada/scng.ads ada/scng.adb ada/sem.ads ada/sem_attr.ads \ - ada/sem_aux.ads ada/sem_ch12.ads ada/sem_ch13.ads ada/sem_ch3.ads \ - ada/sem_ch6.ads ada/sem_ch7.ads ada/sem_ch8.ads ada/sem_disp.ads \ - ada/sem_dist.ads ada/sem_eval.ads ada/sem_mech.ads ada/sem_res.ads \ - ada/sem_scil.ads ada/sem_type.ads ada/sem_util.ads ada/sem_util.adb \ - ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb ada/sinput.ads \ - ada/snames.ads ada/sprint.ads ada/stand.ads ada/stringt.ads \ - ada/style.ads ada/styleg.ads ada/styleg.adb ada/stylesw.ads \ - ada/system.ads ada/s-crc32.ads ada/s-exctab.ads ada/s-htable.ads \ - ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads ada/s-parame.ads \ - ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads ada/s-stache.ads \ - ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb ada/s-string.ads \ - ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads ada/s-wchcon.ads \ - ada/table.ads ada/table.adb ada/targparm.ads ada/tbuild.ads \ - ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads ada/types.ads \ - ada/uintp.ads ada/uintp.adb ada/uname.ads ada/unchconv.ads \ - ada/unchdeal.ads ada/urealp.ads ada/validsw.ads ada/widechar.ads + ada/exp_ch3.ads ada/exp_ch4.ads ada/exp_ch6.ads ada/exp_ch6.adb \ + ada/exp_ch7.ads ada/exp_ch9.ads ada/exp_dbug.ads ada/exp_disp.ads \ + ada/exp_dist.ads ada/exp_intr.ads ada/exp_pakd.ads ada/exp_tss.ads \ + ada/exp_util.ads ada/exp_util.adb ada/exp_vfpt.ads ada/fname.ads \ + ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ + ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads ada/inline.ads \ + ada/interfac.ads ada/itypes.ads ada/lib.ads ada/lib.adb \ + ada/lib-list.adb ada/lib-load.ads ada/lib-sort.adb ada/lib-xref.ads \ + ada/namet.ads ada/namet.adb ada/nlists.ads ada/nlists.adb ada/nmake.ads \ + ada/nmake.adb ada/opt.ads ada/output.ads ada/restrict.ads \ + ada/restrict.adb ada/rident.ads ada/rtsfind.ads ada/rtsfind.adb \ + ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb ada/sem.ads \ + ada/sem_attr.ads ada/sem_aux.ads ada/sem_ch12.ads ada/sem_ch13.ads \ + ada/sem_ch3.ads ada/sem_ch6.ads ada/sem_ch7.ads ada/sem_ch8.ads \ + ada/sem_disp.ads ada/sem_dist.ads ada/sem_eval.ads ada/sem_mech.ads \ + ada/sem_res.ads ada/sem_scil.ads ada/sem_type.ads ada/sem_util.ads \ + ada/sem_util.adb ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb \ + ada/sinput.ads ada/snames.ads ada/sprint.ads ada/stand.ads \ + ada/stringt.ads ada/style.ads ada/styleg.ads ada/styleg.adb \ + ada/stylesw.ads ada/system.ads ada/s-crc32.ads ada/s-exctab.ads \ + ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads \ + ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads \ + ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb \ + ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads \ + ada/s-wchcon.ads ada/table.ads ada/table.adb ada/targparm.ads \ + ada/tbuild.ads ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads \ + ada/types.ads ada/uintp.ads ada/uintp.adb ada/uname.ads \ + ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads ada/validsw.ads \ + ada/widechar.ads ada/exp_ch7.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/a-uncdea.ads ada/alloc.ads ada/atree.ads ada/atree.adb \ @@ -2006,25 +2009,26 @@ ada/exp_pakd.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/casing.ads ada/checks.ads ada/checks.adb ada/debug.ads \ ada/einfo.ads ada/einfo.adb ada/elists.ads ada/err_vars.ads \ ada/errout.ads ada/erroutc.ads ada/eval_fat.ads ada/exp_aggr.ads \ - ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch6.ads ada/exp_ch7.ads \ - ada/exp_dbug.ads ada/exp_pakd.ads ada/exp_pakd.adb ada/exp_tss.ads \ - ada/exp_util.ads ada/exp_util.adb ada/freeze.ads ada/get_targ.ads \ - ada/gnat.ads ada/g-htable.ads ada/hostparm.ads ada/inline.ads \ - ada/itypes.ads ada/layout.ads ada/lib.ads ada/namet.ads ada/nlists.ads \ - ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads \ - ada/restrict.ads ada/rident.ads ada/rtsfind.ads ada/sem.ads \ - ada/sem_aux.ads ada/sem_ch13.ads ada/sem_ch3.ads ada/sem_ch8.ads \ - ada/sem_eval.ads ada/sem_res.ads ada/sem_scil.ads ada/sem_type.ads \ - ada/sem_util.ads ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb \ - ada/sinput.ads ada/snames.ads ada/sprint.ads ada/stand.ads \ - ada/stringt.ads ada/system.ads ada/s-exctab.ads ada/s-htable.ads \ - ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads ada/s-parame.ads \ - ada/s-rident.ads ada/s-soflin.ads ada/s-stache.ads ada/s-stalib.ads \ - ada/s-stoele.ads ada/s-stoele.adb ada/s-string.ads ada/s-traent.ads \ - ada/s-unstyp.ads ada/s-wchcon.ads ada/table.ads ada/table.adb \ - ada/targparm.ads ada/tbuild.ads ada/tbuild.adb ada/tree_io.ads \ - ada/ttypes.ads ada/types.ads ada/uintp.ads ada/uintp.adb \ - ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads ada/validsw.ads + ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch4.ads ada/exp_ch6.ads \ + ada/exp_ch7.ads ada/exp_dbug.ads ada/exp_pakd.ads ada/exp_pakd.adb \ + ada/exp_tss.ads ada/exp_util.ads ada/exp_util.adb ada/freeze.ads \ + ada/get_targ.ads ada/gnat.ads ada/g-htable.ads ada/hostparm.ads \ + ada/inline.ads ada/itypes.ads ada/layout.ads ada/lib.ads ada/namet.ads \ + ada/nlists.ads ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads \ + ada/output.ads ada/restrict.ads ada/rident.ads ada/rtsfind.ads \ + ada/sem.ads ada/sem_aux.ads ada/sem_ch13.ads ada/sem_ch3.ads \ + ada/sem_ch8.ads ada/sem_eval.ads ada/sem_res.ads ada/sem_scil.ads \ + ada/sem_type.ads ada/sem_util.ads ada/sem_warn.ads ada/sinfo.ads \ + ada/sinfo.adb ada/sinput.ads ada/snames.ads ada/sprint.ads \ + ada/stand.ads ada/stringt.ads ada/system.ads ada/s-exctab.ads \ + ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads \ + ada/s-parame.ads ada/s-rident.ads ada/s-soflin.ads ada/s-stache.ads \ + ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb ada/s-string.ads \ + ada/s-traent.ads ada/s-unstyp.ads ada/s-wchcon.ads ada/table.ads \ + ada/table.adb ada/targparm.ads ada/tbuild.ads ada/tbuild.adb \ + ada/tree_io.ads ada/ttypes.ads ada/types.ads ada/uintp.ads \ + ada/uintp.adb ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads \ + ada/validsw.ads ada/exp_prag.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/a-uncdea.ads ada/alloc.ads ada/atree.ads ada/atree.adb \ @@ -3022,12 +3026,12 @@ ada/sem_aggr.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/casing.ads ada/checks.ads ada/checks.adb ada/csets.ads \ ada/debug.ads ada/einfo.ads ada/einfo.adb ada/elists.ads ada/elists.adb \ ada/err_vars.ads ada/errout.ads ada/erroutc.ads ada/eval_fat.ads \ - ada/exp_aggr.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch6.ads \ - ada/exp_ch7.ads ada/exp_disp.ads ada/exp_pakd.ads ada/exp_tss.ads \ - ada/exp_util.ads ada/exp_util.adb ada/expander.ads ada/fname.ads \ - ada/freeze.ads ada/get_targ.ads ada/gnat.ads ada/g-htable.ads \ - ada/hostparm.ads ada/inline.ads ada/interfac.ads ada/itypes.ads \ - ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb \ + ada/exp_aggr.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch4.ads \ + ada/exp_ch6.ads ada/exp_ch7.ads ada/exp_disp.ads ada/exp_pakd.ads \ + ada/exp_tss.ads ada/exp_util.ads ada/exp_util.adb ada/expander.ads \ + ada/fname.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ + ada/g-htable.ads ada/hostparm.ads ada/inline.ads ada/interfac.ads \ + ada/itypes.ads ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb \ ada/namet-sp.ads ada/nlists.ads ada/nlists.adb ada/nmake.ads \ ada/nmake.adb ada/opt.ads ada/output.ads ada/restrict.ads \ ada/rident.ads ada/rtsfind.ads ada/scans.ads ada/scn.ads ada/scng.ads \ @@ -3055,32 +3059,32 @@ ada/sem_attr.o : ada/ada.ads ada/a-charac.ads ada/a-chlat1.ads \ ada/checks.adb ada/csets.ads ada/debug.ads ada/debug_a.ads \ ada/einfo.ads ada/einfo.adb ada/elists.ads ada/err_vars.ads \ ada/errout.ads ada/erroutc.ads ada/eval_fat.ads ada/exp_aggr.ads \ - ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch6.ads ada/exp_ch7.ads \ - ada/exp_disp.ads ada/exp_dist.ads ada/exp_pakd.ads ada/exp_tss.ads \ - ada/exp_util.ads ada/exp_util.adb ada/expander.ads ada/fname.ads \ - ada/freeze.ads ada/get_targ.ads ada/gnat.ads ada/g-htable.ads \ - ada/gnatvsn.ads ada/hostparm.ads ada/inline.ads ada/itypes.ads \ - ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/nlists.ads \ - ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads \ - ada/restrict.ads ada/rident.ads ada/rtsfind.ads ada/scans.ads \ - ada/sdefault.ads ada/sem.ads ada/sem_aggr.ads ada/sem_attr.ads \ - ada/sem_attr.adb ada/sem_aux.ads ada/sem_cat.ads ada/sem_ch10.ads \ - ada/sem_ch13.ads ada/sem_ch3.ads ada/sem_ch4.ads ada/sem_ch6.ads \ - ada/sem_ch8.ads ada/sem_disp.ads ada/sem_dist.ads ada/sem_elab.ads \ - ada/sem_elim.ads ada/sem_eval.ads ada/sem_eval.adb ada/sem_intr.ads \ - ada/sem_res.ads ada/sem_res.adb ada/sem_scil.ads ada/sem_type.ads \ - ada/sem_util.ads ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb \ - ada/sinput.ads ada/sinput.adb ada/snames.ads ada/snames.adb \ - ada/sprint.ads ada/stand.ads ada/stringt.ads ada/stringt.adb \ - ada/style.ads ada/styleg.ads ada/styleg.adb ada/stylesw.ads \ - ada/system.ads ada/s-carun8.ads ada/s-exctab.ads ada/s-exctab.adb \ - ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads \ - ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads \ - ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb \ - ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads ada/s-wchcon.ads \ - ada/table.ads ada/table.adb ada/targparm.ads ada/tbuild.ads \ - ada/tbuild.adb ada/tree_io.ads ada/ttypef.ads ada/ttypes.ads \ - ada/types.ads ada/types.adb ada/uintp.ads ada/uintp.adb \ + ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch4.ads ada/exp_ch6.ads \ + ada/exp_ch7.ads ada/exp_disp.ads ada/exp_dist.ads ada/exp_pakd.ads \ + ada/exp_tss.ads ada/exp_util.ads ada/exp_util.adb ada/expander.ads \ + ada/fname.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ + ada/g-htable.ads ada/gnatvsn.ads ada/hostparm.ads ada/inline.ads \ + ada/itypes.ads ada/lib.ads ada/lib-xref.ads ada/namet.ads \ + ada/nlists.ads ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads \ + ada/output.ads ada/restrict.ads ada/rident.ads ada/rtsfind.ads \ + ada/scans.ads ada/sdefault.ads ada/sem.ads ada/sem_aggr.ads \ + ada/sem_attr.ads ada/sem_attr.adb ada/sem_aux.ads ada/sem_cat.ads \ + ada/sem_ch10.ads ada/sem_ch13.ads ada/sem_ch3.ads ada/sem_ch4.ads \ + ada/sem_ch6.ads ada/sem_ch8.ads ada/sem_disp.ads ada/sem_dist.ads \ + ada/sem_elab.ads ada/sem_elim.ads ada/sem_eval.ads ada/sem_eval.adb \ + ada/sem_intr.ads ada/sem_res.ads ada/sem_res.adb ada/sem_scil.ads \ + ada/sem_type.ads ada/sem_util.ads ada/sem_warn.ads ada/sinfo.ads \ + ada/sinfo.adb ada/sinput.ads ada/sinput.adb ada/snames.ads \ + ada/snames.adb ada/sprint.ads ada/stand.ads ada/stringt.ads \ + ada/stringt.adb ada/style.ads ada/styleg.ads ada/styleg.adb \ + ada/stylesw.ads ada/system.ads ada/s-carun8.ads ada/s-exctab.ads \ + ada/s-exctab.adb ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads \ + ada/s-os_lib.ads ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads \ + ada/s-soflin.ads ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads \ + ada/s-stoele.adb ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads \ + ada/s-wchcon.ads ada/table.ads ada/table.adb ada/targparm.ads \ + ada/tbuild.ads ada/tbuild.adb ada/tree_io.ads ada/ttypef.ads \ + ada/ttypes.ads ada/types.ads ada/types.adb ada/uintp.ads ada/uintp.adb \ ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads ada/urealp.adb \ ada/validsw.ads ada/widechar.ads @@ -3271,35 +3275,35 @@ ada/sem_ch3.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/debug.ads ada/einfo.ads ada/einfo.adb ada/elists.ads ada/elists.adb \ ada/err_vars.ads ada/errout.ads ada/erroutc.ads ada/eval_fat.ads \ ada/exp_aggr.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch3.ads \ - ada/exp_ch6.ads ada/exp_ch7.ads ada/exp_ch9.ads ada/exp_disp.ads \ - ada/exp_dist.ads ada/exp_pakd.ads ada/exp_tss.ads ada/exp_util.ads \ - ada/exp_util.adb ada/fname.ads ada/freeze.ads ada/get_targ.ads \ - ada/gnat.ads ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads \ - ada/inline.ads ada/interfac.ads ada/itypes.ads ada/layout.ads \ - ada/lib.ads ada/lib.adb ada/lib-list.adb ada/lib-sort.adb \ - ada/lib-xref.ads ada/namet.ads ada/namet.adb ada/nlists.ads \ - ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads \ - ada/restrict.ads ada/rident.ads ada/rtsfind.ads ada/scans.ads \ - ada/scn.ads ada/scng.ads ada/scng.adb ada/sem.ads ada/sem_attr.ads \ - ada/sem_aux.ads ada/sem_case.ads ada/sem_case.adb ada/sem_cat.ads \ - ada/sem_cat.adb ada/sem_ch13.ads ada/sem_ch3.ads ada/sem_ch3.adb \ - ada/sem_ch6.ads ada/sem_ch7.ads ada/sem_ch8.ads ada/sem_disp.ads \ - ada/sem_dist.ads ada/sem_elim.ads ada/sem_eval.ads ada/sem_eval.adb \ - ada/sem_mech.ads ada/sem_res.ads ada/sem_scil.ads ada/sem_smem.ads \ - ada/sem_type.ads ada/sem_util.ads ada/sem_util.adb ada/sem_warn.ads \ - ada/sinfo.ads ada/sinfo.adb ada/sinput.ads ada/snames.ads \ - ada/sprint.ads ada/stand.ads ada/stringt.ads ada/stringt.adb \ - ada/style.ads ada/styleg.ads ada/styleg.adb ada/stylesw.ads \ - ada/system.ads ada/s-crc32.ads ada/s-exctab.ads ada/s-htable.ads \ - ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads ada/s-parame.ads \ - ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads ada/s-stache.ads \ - ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb ada/s-string.ads \ - ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads ada/s-wchcon.ads \ - ada/table.ads ada/table.adb ada/targparm.ads ada/tbuild.ads \ - ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads ada/types.ads \ - ada/uintp.ads ada/uintp.adb ada/uname.ads ada/unchconv.ads \ - ada/unchdeal.ads ada/urealp.ads ada/urealp.adb ada/validsw.ads \ - ada/widechar.ads + ada/exp_ch4.ads ada/exp_ch6.ads ada/exp_ch7.ads ada/exp_ch9.ads \ + ada/exp_disp.ads ada/exp_dist.ads ada/exp_pakd.ads ada/exp_tss.ads \ + ada/exp_util.ads ada/exp_util.adb ada/fname.ads ada/freeze.ads \ + ada/get_targ.ads ada/gnat.ads ada/g-hesorg.ads ada/g-htable.ads \ + ada/hostparm.ads ada/inline.ads ada/interfac.ads ada/itypes.ads \ + ada/layout.ads ada/lib.ads ada/lib.adb ada/lib-list.adb \ + ada/lib-sort.adb ada/lib-xref.ads ada/namet.ads ada/namet.adb \ + ada/nlists.ads ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads \ + ada/output.ads ada/restrict.ads ada/rident.ads ada/rtsfind.ads \ + ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb ada/sem.ads \ + ada/sem_attr.ads ada/sem_aux.ads ada/sem_case.ads ada/sem_case.adb \ + ada/sem_cat.ads ada/sem_cat.adb ada/sem_ch13.ads ada/sem_ch3.ads \ + ada/sem_ch3.adb ada/sem_ch6.ads ada/sem_ch7.ads ada/sem_ch8.ads \ + ada/sem_disp.ads ada/sem_dist.ads ada/sem_elim.ads ada/sem_eval.ads \ + ada/sem_eval.adb ada/sem_mech.ads ada/sem_res.ads ada/sem_scil.ads \ + ada/sem_smem.ads ada/sem_type.ads ada/sem_util.ads ada/sem_util.adb \ + ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb ada/sinput.ads \ + ada/snames.ads ada/sprint.ads ada/stand.ads ada/stringt.ads \ + ada/stringt.adb ada/style.ads ada/styleg.ads ada/styleg.adb \ + ada/stylesw.ads ada/system.ads ada/s-crc32.ads ada/s-exctab.ads \ + ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads \ + ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads \ + ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb \ + ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads \ + ada/s-wchcon.ads ada/table.ads ada/table.adb ada/targparm.ads \ + ada/tbuild.ads ada/tbuild.adb ada/tree_io.ads ada/ttypes.ads \ + ada/types.ads ada/uintp.ads ada/uintp.adb ada/uname.ads \ + ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads ada/urealp.adb \ + ada/validsw.ads ada/widechar.ads ada/sem_ch4.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/a-uncdea.ads ada/alloc.ads ada/atree.ads ada/atree.adb \ @@ -3338,34 +3342,34 @@ ada/sem_ch5.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/casing.ads ada/checks.ads ada/checks.adb ada/csets.ads \ ada/debug.ads ada/debug_a.ads ada/einfo.ads ada/einfo.adb \ ada/elists.ads ada/err_vars.ads ada/errout.ads ada/erroutc.ads \ - ada/eval_fat.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch6.ads \ - ada/exp_ch7.ads ada/exp_code.ads ada/exp_disp.ads ada/exp_pakd.ads \ - ada/exp_tss.ads ada/exp_util.ads ada/expander.ads ada/fname.ads \ - ada/freeze.ads ada/get_targ.ads ada/gnat.ads ada/g-hesorg.ads \ - ada/g-htable.ads ada/hostparm.ads ada/interfac.ads ada/itypes.ads \ - ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb ada/nlists.ads \ - ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads \ - ada/par_sco.ads ada/restrict.ads ada/rident.ads ada/rtsfind.ads \ - ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb ada/sem.ads \ - ada/sem_aggr.ads ada/sem_attr.ads ada/sem_aux.ads ada/sem_case.ads \ - ada/sem_case.adb ada/sem_cat.ads ada/sem_ch13.ads ada/sem_ch3.ads \ - ada/sem_ch4.ads ada/sem_ch5.ads ada/sem_ch5.adb ada/sem_ch6.ads \ - ada/sem_ch8.ads ada/sem_disp.ads ada/sem_dist.ads ada/sem_elab.ads \ - ada/sem_elim.ads ada/sem_eval.ads ada/sem_eval.adb ada/sem_intr.ads \ - ada/sem_res.ads ada/sem_res.adb ada/sem_scil.ads ada/sem_type.ads \ - ada/sem_util.ads ada/sem_util.adb ada/sem_warn.ads ada/sem_warn.adb \ - ada/sinfo.ads ada/sinfo.adb ada/sinput.ads ada/snames.ads \ - ada/sprint.ads ada/stand.ads ada/stringt.ads ada/stringt.adb \ - ada/style.ads ada/styleg.ads ada/styleg.adb ada/stylesw.ads \ - ada/system.ads ada/s-crc32.ads ada/s-exctab.ads ada/s-htable.ads \ - ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads ada/s-parame.ads \ - ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads ada/s-stache.ads \ - ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb ada/s-string.ads \ - ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads ada/s-wchcon.ads \ - ada/table.ads ada/table.adb ada/targparm.ads ada/tbuild.ads \ - ada/tree_io.ads ada/ttypes.ads ada/types.ads ada/uintp.ads \ - ada/uintp.adb ada/uname.ads ada/unchconv.ads ada/unchdeal.ads \ - ada/urealp.ads ada/validsw.ads ada/widechar.ads + ada/eval_fat.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch4.ads \ + ada/exp_ch6.ads ada/exp_ch7.ads ada/exp_code.ads ada/exp_disp.ads \ + ada/exp_pakd.ads ada/exp_tss.ads ada/exp_util.ads ada/expander.ads \ + ada/fname.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ + ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads ada/interfac.ads \ + ada/itypes.ads ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb \ + ada/nlists.ads ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads \ + ada/output.ads ada/par_sco.ads ada/restrict.ads ada/rident.ads \ + ada/rtsfind.ads ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb \ + ada/sem.ads ada/sem_aggr.ads ada/sem_attr.ads ada/sem_aux.ads \ + ada/sem_case.ads ada/sem_case.adb ada/sem_cat.ads ada/sem_ch13.ads \ + ada/sem_ch3.ads ada/sem_ch4.ads ada/sem_ch5.ads ada/sem_ch5.adb \ + ada/sem_ch6.ads ada/sem_ch8.ads ada/sem_disp.ads ada/sem_dist.ads \ + ada/sem_elab.ads ada/sem_elim.ads ada/sem_eval.ads ada/sem_eval.adb \ + ada/sem_intr.ads ada/sem_res.ads ada/sem_res.adb ada/sem_scil.ads \ + ada/sem_type.ads ada/sem_util.ads ada/sem_util.adb ada/sem_warn.ads \ + ada/sem_warn.adb ada/sinfo.ads ada/sinfo.adb ada/sinput.ads \ + ada/snames.ads ada/sprint.ads ada/stand.ads ada/stringt.ads \ + ada/stringt.adb ada/style.ads ada/styleg.ads ada/styleg.adb \ + ada/stylesw.ads ada/system.ads ada/s-crc32.ads ada/s-exctab.ads \ + ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads \ + ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads \ + ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb \ + ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads \ + ada/s-wchcon.ads ada/table.ads ada/table.adb ada/targparm.ads \ + ada/tbuild.ads ada/tree_io.ads ada/ttypes.ads ada/types.ads \ + ada/uintp.ads ada/uintp.adb ada/uname.ads ada/unchconv.ads \ + ada/unchdeal.ads ada/urealp.ads ada/validsw.ads ada/widechar.ads ada/sem_ch6.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/a-uncdea.ads ada/alloc.ads ada/atree.ads ada/atree.adb \ @@ -3469,33 +3473,34 @@ ada/sem_ch9.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/casing.ads ada/checks.ads ada/checks.adb ada/csets.ads \ ada/debug.ads ada/debug_a.ads ada/einfo.ads ada/einfo.adb \ ada/elists.ads ada/err_vars.ads ada/errout.ads ada/erroutc.ads \ - ada/eval_fat.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch6.ads \ - ada/exp_ch7.ads ada/exp_ch9.ads ada/exp_disp.ads ada/exp_pakd.ads \ - ada/exp_tss.ads ada/exp_util.ads ada/expander.ads ada/fname.ads \ - ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ - ada/g-htable.ads ada/hostparm.ads ada/interfac.ads ada/itypes.ads \ - ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb ada/nlists.ads \ - ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads ada/output.ads \ - ada/restrict.ads ada/restrict.adb ada/rident.ads ada/rtsfind.ads \ - ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb ada/sem.ads \ - ada/sem_aggr.ads ada/sem_attr.ads ada/sem_aux.ads ada/sem_cat.ads \ - ada/sem_ch13.ads ada/sem_ch3.ads ada/sem_ch4.ads ada/sem_ch5.ads \ - ada/sem_ch6.ads ada/sem_ch8.ads ada/sem_ch9.ads ada/sem_ch9.adb \ - ada/sem_disp.ads ada/sem_dist.ads ada/sem_elab.ads ada/sem_elim.ads \ - ada/sem_eval.ads ada/sem_intr.ads ada/sem_res.ads ada/sem_res.adb \ - ada/sem_scil.ads ada/sem_type.ads ada/sem_util.ads ada/sem_util.adb \ - ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb ada/sinput.ads \ - ada/sinput.adb ada/snames.ads ada/sprint.ads ada/stand.ads \ - ada/stringt.ads ada/style.ads ada/styleg.ads ada/styleg.adb \ - ada/stylesw.ads ada/system.ads ada/s-crc32.ads ada/s-exctab.ads \ - ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads ada/s-os_lib.ads \ - ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads ada/s-soflin.ads \ - ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads ada/s-stoele.adb \ - ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads ada/s-utf_32.ads \ - ada/s-wchcon.ads ada/table.ads ada/table.adb ada/targparm.ads \ - ada/tbuild.ads ada/tree_io.ads ada/ttypes.ads ada/types.ads \ - ada/uintp.ads ada/uintp.adb ada/uname.ads ada/unchconv.ads \ - ada/unchdeal.ads ada/urealp.ads ada/validsw.ads ada/widechar.ads + ada/eval_fat.ads ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch4.ads \ + ada/exp_ch6.ads ada/exp_ch7.ads ada/exp_ch9.ads ada/exp_disp.ads \ + ada/exp_pakd.ads ada/exp_tss.ads ada/exp_util.ads ada/expander.ads \ + ada/fname.ads ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads \ + ada/gnat.ads ada/g-htable.ads ada/hostparm.ads ada/interfac.ads \ + ada/itypes.ads ada/lib.ads ada/lib-xref.ads ada/namet.ads ada/namet.adb \ + ada/nlists.ads ada/nlists.adb ada/nmake.ads ada/nmake.adb ada/opt.ads \ + ada/output.ads ada/restrict.ads ada/restrict.adb ada/rident.ads \ + ada/rtsfind.ads ada/scans.ads ada/scn.ads ada/scng.ads ada/scng.adb \ + ada/sem.ads ada/sem_aggr.ads ada/sem_attr.ads ada/sem_aux.ads \ + ada/sem_cat.ads ada/sem_ch13.ads ada/sem_ch3.ads ada/sem_ch4.ads \ + ada/sem_ch5.ads ada/sem_ch6.ads ada/sem_ch8.ads ada/sem_ch9.ads \ + ada/sem_ch9.adb ada/sem_disp.ads ada/sem_dist.ads ada/sem_elab.ads \ + ada/sem_elim.ads ada/sem_eval.ads ada/sem_intr.ads ada/sem_res.ads \ + ada/sem_res.adb ada/sem_scil.ads ada/sem_type.ads ada/sem_util.ads \ + ada/sem_util.adb ada/sem_warn.ads ada/sinfo.ads ada/sinfo.adb \ + ada/sinput.ads ada/sinput.adb ada/snames.ads ada/sprint.ads \ + ada/stand.ads ada/stringt.ads ada/style.ads ada/styleg.ads \ + ada/styleg.adb ada/stylesw.ads ada/system.ads ada/s-crc32.ads \ + ada/s-exctab.ads ada/s-htable.ads ada/s-imenne.ads ada/s-memory.ads \ + ada/s-os_lib.ads ada/s-parame.ads ada/s-rident.ads ada/s-secsta.ads \ + ada/s-soflin.ads ada/s-stache.ads ada/s-stalib.ads ada/s-stoele.ads \ + ada/s-stoele.adb ada/s-string.ads ada/s-traent.ads ada/s-unstyp.ads \ + ada/s-utf_32.ads ada/s-wchcon.ads ada/table.ads ada/table.adb \ + ada/targparm.ads ada/tbuild.ads ada/tree_io.ads ada/ttypes.ads \ + ada/types.ads ada/uintp.ads ada/uintp.adb ada/uname.ads \ + ada/unchconv.ads ada/unchdeal.ads ada/urealp.ads ada/validsw.ads \ + ada/widechar.ads ada/sem_disp.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/a-uncdea.ads ada/alloc.ads ada/atree.ads ada/atree.adb \ @@ -3699,12 +3704,12 @@ ada/sem_res.o : ada/ada.ads ada/a-except.ads ada/a-unccon.ads \ ada/debug.ads ada/debug_a.ads ada/debug_a.adb ada/einfo.ads \ ada/einfo.adb ada/elists.ads ada/elists.adb ada/err_vars.ads \ ada/errout.ads ada/erroutc.ads ada/eval_fat.ads ada/exp_aggr.ads \ - ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch6.ads ada/exp_ch7.ads \ - ada/exp_disp.ads ada/exp_dist.ads ada/exp_pakd.ads ada/exp_tss.ads \ - ada/exp_util.ads ada/exp_util.adb ada/expander.ads ada/fname.ads \ - ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads ada/gnat.ads \ - ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads ada/inline.ads \ - ada/interfac.ads ada/itypes.ads ada/lib.ads ada/lib.adb \ + ada/exp_ch11.ads ada/exp_ch2.ads ada/exp_ch4.ads ada/exp_ch6.ads \ + ada/exp_ch7.ads ada/exp_disp.ads ada/exp_dist.ads ada/exp_pakd.ads \ + ada/exp_tss.ads ada/exp_util.ads ada/exp_util.adb ada/expander.ads \ + ada/fname.ads ada/fname-uf.ads ada/freeze.ads ada/get_targ.ads \ + ada/gnat.ads ada/g-hesorg.ads ada/g-htable.ads ada/hostparm.ads \ + ada/inline.ads ada/interfac.ads ada/itypes.ads ada/lib.ads ada/lib.adb \ ada/lib-list.adb ada/lib-load.ads ada/lib-sort.adb ada/lib-xref.ads \ ada/namet.ads ada/namet.adb ada/nlists.ads ada/nlists.adb ada/nmake.ads \ ada/nmake.adb ada/opt.ads ada/output.ads ada/restrict.ads \ diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in index cf717ac39cd..c9221fb5022 100644 --- a/gcc/ada/gcc-interface/Makefile.in +++ b/gcc/ada/gcc-interface/Makefile.in @@ -109,8 +109,11 @@ SOME_ADAFLAGS =-gnata FORCE_DEBUG_ADAFLAGS = -g GNATLIBFLAGS = -gnatpg -nostdinc GNATLIBCFLAGS = -g -O2 +# Pretend that _Unwind_GetIPInfo is available for the target by default. This +# should be autodetected during the configuration of libada and passed down to +# here, but we need something for --disable-libada and hope for the best. GNATLIBCFLAGS_FOR_C = $(GNATLIBCFLAGS) $(TARGET_LIBGCC2_CFLAGS) -fexceptions \ - -DIN_RTS + -DIN_RTS -DHAVE_GETIPINFO ALL_ADAFLAGS = $(CFLAGS) $(ADA_CFLAGS) $(ADAFLAGS) MOST_ADAFLAGS = $(CFLAGS) $(ADA_CFLAGS) $(SOME_ADAFLAGS) THREAD_KIND = native @@ -2422,6 +2425,7 @@ gnatlib-shared-default: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS) $(TARGET_LIBGCC2_CFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib @@ -2447,6 +2451,7 @@ gnatlib-shared-dual: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib-shared-default @@ -2455,6 +2460,7 @@ gnatlib-shared-dual: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib @@ -2464,6 +2470,7 @@ gnatlib-shared-dual-win32: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS) $(TARGET_LIBGCC2_CFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib-shared-win32 @@ -2472,6 +2479,7 @@ gnatlib-shared-dual-win32: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib @@ -2485,6 +2493,7 @@ gnatlib-shared-win32: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS) $(TARGET_LIBGCC2_CFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib @@ -2503,7 +2512,7 @@ gnatlib-shared-darwin: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS) $(TARGET_LIBGCC2_CFLAGS) \ - -fno-common" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C) -fno-common" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib @@ -2531,6 +2540,7 @@ gnatlib-shared-vms: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ gnatlib @@ -2559,6 +2569,7 @@ gnatlib-shared: $(MAKE) $(FLAGS_TO_PASS) \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ TARGET_LIBGCC2_CFLAGS="$(TARGET_LIBGCC2_CFLAGS)" \ @@ -2572,6 +2583,7 @@ gnatlib-sjlj: EH_MECHANISM="" \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ TARGET_LIBGCC2_CFLAGS="$(TARGET_LIBGCC2_CFLAGS)" gnatlib @@ -2584,6 +2596,7 @@ gnatlib-zcx: EH_MECHANISM="-gcc" \ GNATLIBFLAGS="$(GNATLIBFLAGS)" \ GNATLIBCFLAGS="$(GNATLIBCFLAGS)" \ + GNATLIBCFLAGS_FOR_C="$(GNATLIBCFLAGS_FOR_C)" \ MULTISUBDIR="$(MULTISUBDIR)" \ THREAD_KIND="$(THREAD_KIND)" \ TARGET_LIBGCC2_CFLAGS="$(TARGET_LIBGCC2_CFLAGS)" gnatlib diff --git a/gcc/ada/gcc-interface/ada-tree.h b/gcc/ada/gcc-interface/ada-tree.h index 94b18bde6b5..67a16ef0eb8 100644 --- a/gcc/ada/gcc-interface/ada-tree.h +++ b/gcc/ada/gcc-interface/ada-tree.h @@ -65,11 +65,11 @@ do { \ /* For RECORD_TYPE, UNION_TYPE, and QUAL_UNION_TYPE, nonzero if this is a record being used as a fat pointer (only true for RECORD_TYPE). */ -#define TYPE_IS_FAT_POINTER_P(NODE) \ +#define TYPE_FAT_POINTER_P(NODE) \ TYPE_LANG_FLAG_0 (RECORD_OR_UNION_CHECK (NODE)) -#define TYPE_FAT_POINTER_P(NODE) \ - (TREE_CODE (NODE) == RECORD_TYPE && TYPE_IS_FAT_POINTER_P (NODE)) +#define TYPE_IS_FAT_POINTER_P(NODE) \ + (TREE_CODE (NODE) == RECORD_TYPE && TYPE_FAT_POINTER_P (NODE)) /* For integral types and array types, nonzero if this is a packed array type used for bit-packed types. Such types should not be extended to a larger @@ -117,15 +117,15 @@ do { \ TYPE_LANG_FLAG_3 (INTEGER_TYPE_CHECK (NODE)) /* True if NODE is a thin pointer. */ -#define TYPE_THIN_POINTER_P(NODE) \ +#define TYPE_IS_THIN_POINTER_P(NODE) \ (POINTER_TYPE_P (NODE) \ && TREE_CODE (TREE_TYPE (NODE)) == RECORD_TYPE \ && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (NODE))) /* True if TYPE is either a fat or thin pointer to an unconstrained array. */ -#define TYPE_FAT_OR_THIN_POINTER_P(NODE) \ - (TYPE_FAT_POINTER_P (NODE) || TYPE_THIN_POINTER_P (NODE)) +#define TYPE_IS_FAT_OR_THIN_POINTER_P(NODE) \ + (TYPE_IS_FAT_POINTER_P (NODE) || TYPE_IS_THIN_POINTER_P (NODE)) /* For INTEGER_TYPEs, nonzero if the type has a biased representation. */ #define TYPE_BIASED_REPRESENTATION_P(NODE) \ @@ -143,7 +143,6 @@ do { \ is a dummy type, made to correspond to a private or incomplete type. */ #define TYPE_DUMMY_P(NODE) TYPE_LANG_FLAG_4 (NODE) -/* True if TYPE is such a dummy type. */ #define TYPE_IS_DUMMY_P(NODE) \ ((TREE_CODE (NODE) == VOID_TYPE || TREE_CODE (NODE) == RECORD_TYPE \ || TREE_CODE (NODE) == UNION_TYPE || TREE_CODE (NODE) == ENUMERAL_TYPE) \ @@ -160,7 +159,10 @@ do { \ /* For a RECORD_TYPE, nonzero if this was made just to supply needed padding or alignment. */ -#define TYPE_IS_PADDING_P(NODE) TYPE_LANG_FLAG_5 (RECORD_TYPE_CHECK (NODE)) +#define TYPE_PADDING_P(NODE) TYPE_LANG_FLAG_5 (RECORD_TYPE_CHECK (NODE)) + +#define TYPE_IS_PADDING_P(NODE) \ + (TREE_CODE (NODE) == RECORD_TYPE && TYPE_PADDING_P (NODE)) /* True if TYPE can alias any other types. */ #define TYPE_UNIVERSAL_ALIASING_P(NODE) TYPE_LANG_FLAG_6 (NODE) diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index f2f0f159abd..c4d5e26582a 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -135,7 +135,7 @@ static tree gnat_to_gnu_param (Entity_Id, Mechanism_Type, Entity_Id, bool, bool *); static tree gnat_to_gnu_field (Entity_Id, tree, int, bool, bool); static bool same_discriminant_p (Entity_Id, Entity_Id); -static bool array_type_has_nonaliased_component (Entity_Id, tree); +static bool array_type_has_nonaliased_component (tree, Entity_Id); static bool compile_time_known_address_p (Node_Id); static bool cannot_be_superflat_p (Node_Id); static void components_to_record (tree, Node_Id, tree, int, bool, tree *, @@ -633,7 +633,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) else gnu_type = maybe_pad_type (gnu_type, NULL_TREE, align, gnat_entity, - "PAD", false, definition, true); + false, false, definition, true); } /* If we are defining the object, see if it has a Size value and @@ -676,8 +676,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) despite having a nominal type with self-referential size, we can get the size directly from it. */ if (TREE_CODE (gnu_expr) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_expr, 0))) - == RECORD_TYPE && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_expr, 0))) && TREE_CODE (TREE_OPERAND (gnu_expr, 0)) == VAR_DECL @@ -838,7 +836,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) gnu_object_size = gnu_size ? gnu_size : TYPE_SIZE (gnu_type); if (gnu_size || align > 0) gnu_type = maybe_pad_type (gnu_type, gnu_size, align, gnat_entity, - "PAD", false, definition, + false, false, definition, gnu_size ? true : false); /* If this is a renaming, avoid as much as possible to create a new @@ -852,8 +850,6 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) /* If the renamed object had padding, strip off the reference to the inner object and reset our type. */ if ((TREE_CODE (gnu_expr) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_expr, 0))) - == RECORD_TYPE && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_expr, 0)))) /* Strip useless conversions around the object. */ || (TREE_CODE (gnu_expr) == NOP_EXPR @@ -1017,16 +1013,15 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) && !gnu_expr && TREE_CODE (gnu_type) == RECORD_TYPE && (TYPE_CONTAINS_TEMPLATE_P (gnu_type) - /* Beware that padding might have been introduced - via maybe_pad_type above. */ - || (TYPE_IS_PADDING_P (gnu_type) + /* Beware that padding might have been introduced above. */ + || (TYPE_PADDING_P (gnu_type) && TREE_CODE (TREE_TYPE (TYPE_FIELDS (gnu_type))) == RECORD_TYPE && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (TYPE_FIELDS (gnu_type)))))) { tree template_field - = TYPE_IS_PADDING_P (gnu_type) + = TYPE_PADDING_P (gnu_type) ? TYPE_FIELDS (TREE_TYPE (TYPE_FIELDS (gnu_type))) : TYPE_FIELDS (gnu_type); @@ -1050,17 +1045,16 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) if (gnu_expr && TREE_CODE (gnu_type) != UNCONSTRAINED_ARRAY_TYPE && !CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_type)) - && !(TREE_CODE (gnu_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_type) - && (CONTAINS_PLACEHOLDER_P - (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type))))))) + && !(TYPE_IS_PADDING_P (gnu_type) + && CONTAINS_PLACEHOLDER_P + (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type)))))) gnu_expr = convert (gnu_type, gnu_expr); /* If this is a pointer and it does not have an initializing expression, initialize it to NULL, unless the object is imported. */ if (definition - && (POINTER_TYPE_P (gnu_type) || TYPE_FAT_POINTER_P (gnu_type)) + && (POINTER_TYPE_P (gnu_type) || TYPE_IS_FAT_POINTER_P (gnu_type)) && !Is_Imported (gnat_entity) && !gnu_expr) gnu_expr = integer_zero_node; @@ -1279,10 +1273,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) if (gnu_expr && TREE_CODE (gnu_type) != UNCONSTRAINED_ARRAY_TYPE && !CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_type)) - && !(TREE_CODE (gnu_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_type) - && (CONTAINS_PLACEHOLDER_P - (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type))))))) + && !(TYPE_IS_PADDING_P (gnu_type) + && CONTAINS_PLACEHOLDER_P + (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (gnu_type)))))) gnu_expr = convert (gnu_type, gnu_expr); /* If this name is external or there was a name specified, use it, @@ -1304,8 +1297,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) && gnu_expr && TREE_CONSTANT (gnu_expr) && AGGREGATE_TYPE_P (gnu_type) && host_integerp (TYPE_SIZE_UNIT (gnu_type), 1) - && !(TREE_CODE (gnu_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_type) + && !(TYPE_IS_PADDING_P (gnu_type) && !host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (TYPE_FIELDS (gnu_type))), 1))) static_p = true; @@ -1687,7 +1679,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) gnu_field_type, gnu_type, 1, 0, 0, 0); finish_record_type (gnu_type, gnu_field, 0, false); - TYPE_IS_PADDING_P (gnu_type) = 1; + TYPE_PADDING_P (gnu_type) = 1; relate_alias_sets (gnu_type, gnu_field_type, ALIAS_SET_COPY); } @@ -1835,7 +1827,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) /* Do not finalize this record type since the types of its fields are still incomplete at this point. */ finish_record_type (gnu_fat_type, tem, 0, true); - TYPE_IS_FAT_POINTER_P (gnu_fat_type) = 1; + TYPE_FAT_POINTER_P (gnu_fat_type) = 1; /* Build a reference to the template from a PLACEHOLDER_EXPR that is the fat pointer. This will be used to access the individual @@ -1971,7 +1963,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) { tem = build_array_type (tem, gnu_index_types[index]); TYPE_MULTI_ARRAY_P (tem) = (index > 0); - if (array_type_has_nonaliased_component (gnat_entity, tem)) + if (array_type_has_nonaliased_component (tem, gnat_entity)) TYPE_NONALIASED_COMPONENT (tem) = 1; } @@ -2320,7 +2312,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) { gnu_type = build_array_type (gnu_type, gnu_index_types[index]); TYPE_MULTI_ARRAY_P (gnu_type) = (index > 0); - if (array_type_has_nonaliased_component (gnat_entity, gnu_type)) + if (array_type_has_nonaliased_component (gnu_type, gnat_entity)) TYPE_NONALIASED_COMPONENT (gnu_type) = 1; } @@ -2477,7 +2469,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) gnu_inner = gnu_type; while (TREE_CODE (gnu_inner) == RECORD_TYPE && (TYPE_JUSTIFIED_MODULAR_P (gnu_inner) - || TYPE_IS_PADDING_P (gnu_inner))) + || TYPE_PADDING_P (gnu_inner))) gnu_inner = TREE_TYPE (TYPE_FIELDS (gnu_inner)); /* We need to attach the index type to the type we just made so @@ -2571,7 +2563,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) gnu_type = build_array_type (gnat_to_gnu_type (Component_Type (gnat_entity)), gnu_index_type); - if (array_type_has_nonaliased_component (gnat_entity, gnu_type)) + if (array_type_has_nonaliased_component (gnu_type, gnat_entity)) TYPE_NONALIASED_COMPONENT (gnu_type) = 1; relate_alias_sets (gnu_type, gnu_string_type, ALIAS_SET_COPY); } @@ -2737,15 +2729,16 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) Present (gnat_field); gnat_field = Next_Stored_Discriminant (gnat_field)) if (Present (Corresponding_Discriminant (gnat_field))) - save_gnu_tree - (gnat_field, - build3 (COMPONENT_REF, - get_unpadded_type (Etype (gnat_field)), - gnu_get_parent, - gnat_to_gnu_field_decl (Corresponding_Discriminant - (gnat_field)), - NULL_TREE), - true); + { + tree gnu_field + = gnat_to_gnu_field_decl (Corresponding_Discriminant + (gnat_field)); + save_gnu_tree + (gnat_field, + build3 (COMPONENT_REF, TREE_TYPE (gnu_field), + gnu_get_parent, gnu_field, NULL_TREE), + true); + } /* Then we build the parent subtype. If it has discriminants but the type itself has unknown discriminants, this means that it @@ -2986,8 +2979,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) copy_and_substitute_in_size (gnu_type, gnu_base_type, gnu_subst_list); - if (TREE_CODE (gnu_base_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_base_type)) + if (TYPE_IS_PADDING_P (gnu_base_type)) gnu_unpad_base_type = TREE_TYPE (TYPE_FIELDS (gnu_base_type)); else gnu_unpad_base_type = gnu_base_type; @@ -3097,7 +3089,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) { gnu_size = DECL_SIZE (gnu_old_field); if (TREE_CODE (gnu_field_type) == RECORD_TYPE - && !TYPE_IS_FAT_POINTER_P (gnu_field_type) + && !TYPE_FAT_POINTER_P (gnu_field_type) && host_integerp (TYPE_SIZE (gnu_field_type), 1)) gnu_field_type = make_packable_type (gnu_field_type, true); @@ -3465,7 +3457,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) /* Make sure we can place this into a register. */ TYPE_ALIGN (gnu_type) = MIN (BIGGEST_ALIGNMENT, 2 * POINTER_SIZE); - TYPE_IS_FAT_POINTER_P (gnu_type) = 1; + TYPE_FAT_POINTER_P (gnu_type) = 1; /* Do not finalize this record type since the types of its fields are incomplete. */ @@ -3599,11 +3591,11 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) if ((! in_main_unit || is_from_limited_with) && made_dummy) { tree gnu_old_type - = TYPE_FAT_POINTER_P (gnu_type) + = TYPE_IS_FAT_POINTER_P (gnu_type) ? TYPE_UNCONSTRAINED_ARRAY (gnu_type) : TREE_TYPE (gnu_type); if (esize == POINTER_SIZE - && (got_fat_p || TYPE_FAT_POINTER_P (gnu_type))) + && (got_fat_p || TYPE_IS_FAT_POINTER_P (gnu_type))) gnu_type = build_pointer_type (TYPE_OBJECT_RECORD_TYPE @@ -3915,8 +3907,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) /* If the type is a padded type and the underlying type would not be passed by reference or this function has a foreign convention, return the underlying type. */ - else if (TREE_CODE (gnu_return_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_return_type) + else if (TYPE_IS_PADDING_P (gnu_return_type) && (!default_pass_by_ref (TREE_TYPE (TYPE_FIELDS (gnu_return_type))) || Has_Foreign_Convention (gnat_entity))) @@ -4054,7 +4045,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) between two calls, so they can't be CSE'ed. The latter case also handles by-ref parameters. */ if (POINTER_TYPE_P (gnu_param_type) - || TYPE_FAT_POINTER_P (gnu_param_type)) + || TYPE_IS_FAT_POINTER_P (gnu_param_type)) const_flag = false; } @@ -4417,7 +4408,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) else if ((TREE_CODE (gnu_type) == RECORD_TYPE || TREE_CODE (gnu_type) == UNION_TYPE || TREE_CODE (gnu_type) == QUAL_UNION_TYPE) - && !TYPE_IS_FAT_POINTER_P (gnu_type)) + && !TYPE_FAT_POINTER_P (gnu_type)) size = rm_size (gnu_type); else size = TYPE_SIZE (gnu_type); @@ -4446,10 +4437,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) us when we make the new TYPE_DECL below. */ if (gnu_size || align > 0) gnu_type = maybe_pad_type (gnu_type, gnu_size, align, gnat_entity, - "PAD", true, definition, false); + false, !gnu_decl, definition, false); - if (TREE_CODE (gnu_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_type)) + if (TYPE_IS_PADDING_P (gnu_type)) { gnu_entity_name = TYPE_NAME (gnu_type); if (TREE_CODE (gnu_entity_name) == TYPE_DECL) @@ -4566,7 +4556,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) !Comes_From_Source (gnat_entity), debug_info_p, gnat_entity); else - TREE_TYPE (gnu_decl) = gnu_type; + { + TREE_TYPE (gnu_decl) = gnu_type; + TYPE_STUB_DECL (gnu_type) = gnu_decl; + } } if (is_type && !TYPE_IS_DUMMY_P (TREE_TYPE (gnu_decl))) @@ -4609,11 +4602,38 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) superset superset R ----------> D ----------> T + However, for composite types, conversions between derived types are + translated into VIEW_CONVERT_EXPRs so a sequence like: + + type Comp1 is new Comp; + type Comp2 is new Comp; + procedure Proc (C : Comp1); + + C : Comp2; + Proc (Comp1 (C)); + + is translated into: + + C : Comp2; + Proc ((Comp1 &) &VIEW_CONVERT_EXPR (C)); + + and gimplified into: + + C : Comp2; + Comp1 *C.0; + C.0 = (Comp1 *) &C; + Proc (C.0); + + i.e. generates code involving type punning. Therefore, Comp1 needs + to conflict with Comp2 and an alias set copy is required. + The language rules ensure the parent type is already frozen here. */ if (Is_Derived_Type (gnat_entity)) { tree gnu_parent_type = gnat_to_gnu_type (Etype (gnat_entity)); - relate_alias_sets (gnu_type, gnu_parent_type, ALIAS_SET_SUPERSET); + relate_alias_sets (gnu_type, gnu_parent_type, + Is_Composite_Type (gnat_entity) + ? ALIAS_SET_COPY : ALIAS_SET_SUPERSET); } /* Back-annotate the Alignment of the type if not already in the @@ -4705,8 +4725,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) tree gnu_low_bound, gnu_high_bound; /* If this is a padded type, we need to use the underlying type. */ - if (TREE_CODE (gnu_scalar_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_scalar_type)) + if (TYPE_IS_PADDING_P (gnu_scalar_type)) gnu_scalar_type = TREE_TYPE (TYPE_FIELDS (gnu_scalar_type)); /* If this is a floating point type and we haven't set a floating @@ -4852,7 +4871,7 @@ get_unpadded_type (Entity_Id gnat_entity) { tree type = gnat_to_gnu_type (gnat_entity); - if (TREE_CODE (type) == RECORD_TYPE && TYPE_IS_PADDING_P (type)) + if (TYPE_IS_PADDING_P (type)) type = TREE_TYPE (TYPE_FIELDS (type)); return type; @@ -4985,7 +5004,7 @@ gnat_to_gnu_component_type (Entity_Id gnat_array, bool definition, && !Has_Aliased_Components (gnat_array) && !Strict_Alignment (Component_Type (gnat_array)) && TREE_CODE (gnu_type) == RECORD_TYPE - && !TYPE_IS_FAT_POINTER_P (gnu_type) + && !TYPE_FAT_POINTER_P (gnu_type) && host_integerp (TYPE_SIZE (gnu_type), 1)) gnu_type = make_packable_type (gnu_type, false); @@ -5037,7 +5056,7 @@ gnat_to_gnu_component_type (Entity_Id gnat_array, bool definition, orig_type = gnu_type; gnu_type = maybe_pad_type (gnu_type, gnu_comp_size, 0, gnat_array, - "C_PAD", false, definition, true); + true, false, definition, true); /* If a padding record was made, declare it now since it will never be declared otherwise. This is necessary to ensure that its subtrees @@ -5089,8 +5108,7 @@ gnat_to_gnu_param (Entity_Id gnat_param, Mechanism_Type mech, /* If this is either a foreign function or if the underlying type won't be passed by reference, strip off possible padding type. */ - if (TREE_CODE (gnu_param_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_param_type)) + if (TYPE_IS_PADDING_P (gnu_param_type)) { tree unpadded_type = TREE_TYPE (TYPE_FIELDS (gnu_param_type)); @@ -5162,7 +5180,7 @@ gnat_to_gnu_param (Entity_Id gnat_param, Mechanism_Type mech, } /* Fat pointers are passed as thin pointers for foreign conventions. */ - else if (foreign && TYPE_FAT_POINTER_P (gnu_param_type)) + else if (foreign && TYPE_IS_FAT_POINTER_P (gnu_param_type)) gnu_param_type = make_type_from_size (gnu_param_type, size_int (POINTER_SIZE), 0); @@ -5263,21 +5281,38 @@ same_discriminant_p (Entity_Id discr1, Entity_Id discr2) Original_Record_Component (discr1) == Original_Record_Component (discr2); } -/* Return true if the array type specified by GNAT_TYPE and GNU_TYPE has - a non-aliased component in the back-end sense. */ +/* Return true if the array type GNU_TYPE, which represents a dimension of + GNAT_TYPE, has a non-aliased component in the back-end sense. */ static bool -array_type_has_nonaliased_component (Entity_Id gnat_type, tree gnu_type) +array_type_has_nonaliased_component (tree gnu_type, Entity_Id gnat_type) { - /* If the type below this is a multi-array type, then - this does not have aliased components. */ + /* If the array type is not the innermost dimension of the GNAT type, + then it has a non-aliased component. */ if (TREE_CODE (TREE_TYPE (gnu_type)) == ARRAY_TYPE && TYPE_MULTI_ARRAY_P (TREE_TYPE (gnu_type))) return true; + /* If the array type has an aliased component in the front-end sense, + then it also has an aliased component in the back-end sense. */ if (Has_Aliased_Components (gnat_type)) return false; + /* If this is a derived type, then it has a non-aliased component if + and only if its parent type also has one. */ + if (Is_Derived_Type (gnat_type)) + { + tree gnu_parent_type = gnat_to_gnu_type (Etype (gnat_type)); + int index; + if (TREE_CODE (gnu_parent_type) == UNCONSTRAINED_ARRAY_TYPE) + gnu_parent_type + = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_parent_type)))); + for (index = Number_Dimensions (gnat_type) - 1; index > 0; index--) + gnu_parent_type = TREE_TYPE (gnu_parent_type); + return TYPE_NONALIASED_COMPONENT (gnu_parent_type); + } + + /* Otherwise, rely exclusively on properties of the element type. */ return type_for_nonaliased_component_p (TREE_TYPE (gnu_type)); } @@ -5463,7 +5498,7 @@ relate_alias_sets (tree gnu_new_type, tree gnu_old_type, enum alias_set_op op) see the inner types. */ while (TREE_CODE (gnu_old_type) == RECORD_TYPE && (TYPE_JUSTIFIED_MODULAR_P (gnu_old_type) - || TYPE_IS_PADDING_P (gnu_old_type))) + || TYPE_PADDING_P (gnu_old_type))) gnu_old_type = TREE_TYPE (TYPE_FIELDS (gnu_old_type)); /* Unconstrained array types are deemed incomplete and would thus be given @@ -5929,7 +5964,7 @@ make_packable_type (tree type, bool in_record) TYPE_JUSTIFIED_MODULAR_P (new_type) = TYPE_JUSTIFIED_MODULAR_P (type); TYPE_CONTAINS_TEMPLATE_P (new_type) = TYPE_CONTAINS_TEMPLATE_P (type); if (TREE_CODE (type) == RECORD_TYPE) - TYPE_IS_PADDING_P (new_type) = TYPE_IS_PADDING_P (type); + TYPE_PADDING_P (new_type) = TYPE_PADDING_P (type); /* If we are in a record and have a small size, set the alignment to try for an integral mode. Otherwise set it to try for a smaller @@ -5972,7 +6007,7 @@ make_packable_type (tree type, bool in_record) if ((TREE_CODE (new_field_type) == RECORD_TYPE || TREE_CODE (new_field_type) == UNION_TYPE || TREE_CODE (new_field_type) == QUAL_UNION_TYPE) - && !TYPE_IS_FAT_POINTER_P (new_field_type) + && !TYPE_FAT_POINTER_P (new_field_type) && host_integerp (TYPE_SIZE (new_field_type), 1)) new_field_type = make_packable_type (new_field_type, true); @@ -5984,7 +6019,7 @@ make_packable_type (tree type, bool in_record) && (TREE_CODE (new_field_type) == RECORD_TYPE || TREE_CODE (new_field_type) == UNION_TYPE || TREE_CODE (new_field_type) == QUAL_UNION_TYPE) - && !TYPE_IS_FAT_POINTER_P (new_field_type) + && !TYPE_FAT_POINTER_P (new_field_type) && !TYPE_CONTAINS_TEMPLATE_P (new_field_type) && TYPE_ADA_SIZE (new_field_type)) new_size = TYPE_ADA_SIZE (new_field_type); @@ -6013,8 +6048,7 @@ make_packable_type (tree type, bool in_record) /* If this is a padding record, we never want to make the size smaller than what was specified. For QUAL_UNION_TYPE, also copy the size. */ - if ((TREE_CODE (type) == RECORD_TYPE && TYPE_IS_PADDING_P (type)) - || TREE_CODE (type) == QUAL_UNION_TYPE) + if (TYPE_IS_PADDING_P (type) || TREE_CODE (type) == QUAL_UNION_TYPE) { TYPE_SIZE (new_type) = TYPE_SIZE (type); TYPE_SIZE_UNIT (new_type) = TYPE_SIZE_UNIT (type); @@ -6046,25 +6080,20 @@ make_packable_type (tree type, bool in_record) /* Ensure that TYPE has SIZE and ALIGN. Make and return a new padded type if needed. We have already verified that SIZE and TYPE are large enough. - - GNAT_ENTITY and NAME_TRAILER are used to name the resulting record and - to issue a warning. - - IS_USER_TYPE is true if we must complete the original type. - - DEFINITION is true if this type is being defined. - - SAME_RM_SIZE is true if the RM size of the resulting type is to be set - to SIZE too; otherwise, it's set to the RM size of the original type. */ + GNAT_ENTITY is used to name the resulting record and to issue a warning. + IS_COMPONENT_TYPE is true if this is being done for the component type + of an array. IS_USER_TYPE is true if we must complete the original type. + DEFINITION is true if this type is being defined. SAME_RM_SIZE is true + if the RM size of the resulting type is to be set to SIZE too; otherwise, + it's set to the RM size of the original type. */ tree maybe_pad_type (tree type, tree size, unsigned int align, - Entity_Id gnat_entity, const char *name_trailer, + Entity_Id gnat_entity, bool is_component_type, bool is_user_type, bool definition, bool same_rm_size) { tree orig_rm_size = same_rm_size ? NULL_TREE : rm_size (type); tree orig_size = TYPE_SIZE (type); - unsigned int orig_align = align; tree record, field; /* If TYPE is a padded type, see if it agrees with any size and alignment @@ -6072,7 +6101,7 @@ maybe_pad_type (tree type, tree size, unsigned int align, off the padding, since we will either be returning the inner type or repadding it. If no size or alignment is specified, use that of the original padded type. */ - if (TREE_CODE (type) == RECORD_TYPE && TYPE_IS_PADDING_P (type)) + if (TYPE_IS_PADDING_P (type)) { if ((!size || operand_equal_p (round_up (size, @@ -6121,18 +6150,15 @@ maybe_pad_type (tree type, tree size, unsigned int align, generate incorrect debugging information. So make a new record type and name. */ record = make_node (RECORD_TYPE); - TYPE_IS_PADDING_P (record) = 1; + TYPE_PADDING_P (record) = 1; if (Present (gnat_entity)) - TYPE_NAME (record) = create_concat_name (gnat_entity, name_trailer); + TYPE_NAME (record) = create_concat_name (gnat_entity, "PAD"); TYPE_VOLATILE (record) = Present (gnat_entity) && Treat_As_Volatile (gnat_entity); TYPE_ALIGN (record) = align; - if (orig_align) - TYPE_USER_ALIGN (record) = align; - TYPE_SIZE (record) = size ? size : orig_size; TYPE_SIZE_UNIT (record) = convert (sizetype, @@ -6256,7 +6282,7 @@ maybe_pad_type (tree type, tree size, unsigned int align, post_error_ne_tree ("{^ }bits of & unused?", gnat_error_node, gnat_entity, size_diffop (size, orig_size)); - else if (name_trailer[0] == 'C') + else if (is_component_type) post_error_ne_tree ("component of& padded{ by ^ bits}?", gnat_entity, gnat_entity, size_diffop (size, orig_size)); @@ -6447,7 +6473,7 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed, from a component clause. */ if (TREE_CODE (gnu_field_type) == RECORD_TYPE - && !TYPE_IS_FAT_POINTER_P (gnu_field_type) + && !TYPE_FAT_POINTER_P (gnu_field_type) && host_integerp (TYPE_SIZE (gnu_field_type), 1) && (packed == 1 || (gnu_size @@ -6634,7 +6660,7 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed, orig_field_type = gnu_field_type; gnu_field_type = maybe_pad_type (gnu_field_type, gnu_size, 0, gnat_field, - "PAD", false, definition, true); + false, false, definition, true); /* If a padding record was made, declare it now since it will never be declared otherwise. This is necessary to ensure that its subtrees @@ -6677,8 +6703,7 @@ is_variable_size (tree type) if (!TREE_CONSTANT (TYPE_SIZE (type))) return true; - if (TREE_CODE (type) == RECORD_TYPE - && TYPE_IS_PADDING_P (type) + if (TYPE_IS_PADDING_P (type) && !TREE_CONSTANT (DECL_SIZE (TYPE_FIELDS (type)))) return true; @@ -7227,7 +7252,7 @@ annotate_object (Entity_Id gnat_entity, tree gnu_type, tree size, bool by_ref) { if (by_ref) { - if (TYPE_FAT_POINTER_P (gnu_type)) + if (TYPE_IS_FAT_POINTER_P (gnu_type)) gnu_type = TYPE_UNCONSTRAINED_ARRAY (gnu_type); else gnu_type = TREE_TYPE (gnu_type); @@ -7250,6 +7275,23 @@ annotate_object (Entity_Id gnat_entity, tree gnu_type, tree size, bool by_ref) UI_From_Int (TYPE_ALIGN (gnu_type) / BITS_PER_UNIT)); } +/* Return first element of field list whose TREE_PURPOSE is ELEM or whose + DECL_ORIGINAL_FIELD of TREE_PURPOSE is ELEM. Return NULL_TREE if there + is no such element in the list. */ + +static tree +purpose_member_field (const_tree elem, tree list) +{ + while (list) + { + tree field = TREE_PURPOSE (list); + if (elem == field || elem == DECL_ORIGINAL_FIELD (field)) + return list; + list = TREE_CHAIN (list); + } + return NULL_TREE; +} + /* Given GNAT_ENTITY, a record type, and GNU_TYPE, its corresponding GCC type, set Component_Bit_Offset and Esize of the components to the position and size used by Gigi. */ @@ -7273,11 +7315,12 @@ annotate_rep (Entity_Id gnat_entity, tree gnu_type) || (Ekind (gnat_field) == E_Discriminant && !Is_Unchecked_Union (Scope (gnat_field)))) { - tree parent_offset, t; - - t = purpose_member (gnat_to_gnu_field_decl (gnat_field), gnu_list); + tree t = purpose_member_field (gnat_to_gnu_field_decl (gnat_field), + gnu_list); if (t) { + tree parent_offset; + if (type_annotate_only && Is_Tagged_Type (gnat_entity)) { /* In this mode the tag and parent components are not @@ -7394,12 +7437,16 @@ build_subst_list (Entity_Id gnat_subtype, Entity_Id gnat_type, bool definition) gnat_value = Next_Elmt (gnat_value)) /* Ignore access discriminants. */ if (!Is_Access_Type (Etype (Node (gnat_value)))) - gnu_list = tree_cons (gnat_to_gnu_field_decl (gnat_discrim), - elaborate_expression - (Node (gnat_value), gnat_subtype, - get_entity_name (gnat_discrim), definition, - true, false), - gnu_list); + { + tree gnu_field = gnat_to_gnu_field_decl (gnat_discrim); + gnu_list = tree_cons (gnu_field, + convert (TREE_TYPE (gnu_field), + elaborate_expression + (Node (gnat_value), gnat_subtype, + get_entity_name (gnat_discrim), + definition, true, false)), + gnu_list); + } return gnu_list; } @@ -7542,7 +7589,7 @@ validate_size (Uint uint_size, tree gnu_type, Entity_Id gnat_object, /* If this is an access type or a fat pointer, the minimum size is that given by the smallest integral mode that's valid for pointers. */ - if ((TREE_CODE (gnu_type) == POINTER_TYPE) || TYPE_FAT_POINTER_P (gnu_type)) + if (TREE_CODE (gnu_type) == POINTER_TYPE || TYPE_IS_FAT_POINTER_P (gnu_type)) { enum machine_mode p_mode; @@ -7636,8 +7683,7 @@ set_rm_size (Uint uint_size, tree gnu_type, Entity_Id gnat_entity) || (AGGREGATE_TYPE_P (gnu_type) && !(TREE_CODE (gnu_type) == ARRAY_TYPE && TYPE_PACKED_ARRAY_TYPE_P (gnu_type)) - && !(TREE_CODE (gnu_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_type) + && !(TYPE_IS_PADDING_P (gnu_type) && TREE_CODE (TREE_TYPE (TYPE_FIELDS (gnu_type))) == ARRAY_TYPE && TYPE_PACKED_ARRAY_TYPE_P (TREE_TYPE (TYPE_FIELDS (gnu_type)))) && tree_int_cst_lt (size, old_size))) @@ -7660,7 +7706,7 @@ set_rm_size (Uint uint_size, tree gnu_type, Entity_Id gnat_entity) else if ((TREE_CODE (gnu_type) == RECORD_TYPE || TREE_CODE (gnu_type) == UNION_TYPE || TREE_CODE (gnu_type) == QUAL_UNION_TYPE) - && !TYPE_IS_FAT_POINTER_P (gnu_type)) + && !TYPE_FAT_POINTER_P (gnu_type)) SET_TYPE_ADA_SIZE (gnu_type, size); } @@ -7691,6 +7737,10 @@ make_type_from_size (tree type, tree size_tree, bool for_biased) biased_p = (TREE_CODE (type) == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (type)); + /* Integer types with precision 0 are forbidden. */ + if (size == 0) + size = 1; + /* Only do something if the type is not a packed array type and doesn't already have the proper size. */ if (TYPE_PACKED_ARRAY_TYPE_P (type) @@ -7727,7 +7777,7 @@ make_type_from_size (tree type, tree size_tree, bool for_biased) case RECORD_TYPE: /* Do something if this is a fat pointer, in which case we may need to return the thin pointer. */ - if (TYPE_IS_FAT_POINTER_P (type) && size < POINTER_SIZE * 2) + if (TYPE_FAT_POINTER_P (type) && size < POINTER_SIZE * 2) { enum machine_mode p_mode = mode_for_size (size, MODE_INT, 0); if (!targetm.valid_pointer_mode (p_mode)) @@ -7742,7 +7792,7 @@ make_type_from_size (tree type, tree size_tree, bool for_biased) case POINTER_TYPE: /* Only do something if this is a thin pointer, in which case we may need to return the fat pointer. */ - if (TYPE_THIN_POINTER_P (type) && size >= POINTER_SIZE * 2) + if (TYPE_IS_THIN_POINTER_P (type) && size >= POINTER_SIZE * 2) return build_pointer_type (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))); break; @@ -8393,7 +8443,7 @@ rm_size (tree gnu_type) if ((TREE_CODE (gnu_type) == RECORD_TYPE || TREE_CODE (gnu_type) == UNION_TYPE || TREE_CODE (gnu_type) == QUAL_UNION_TYPE) - && !TYPE_IS_FAT_POINTER_P (gnu_type) + && !TYPE_FAT_POINTER_P (gnu_type) && TYPE_ADA_SIZE (gnu_type)) return TYPE_ADA_SIZE (gnu_type); diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index ea1a65d485b..82d193bfc5c 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -124,21 +124,16 @@ extern tree make_aligning_type (tree type, unsigned int align, tree size, /* Ensure that TYPE has SIZE and ALIGN. Make and return a new padded type if needed. We have already verified that SIZE and TYPE are large enough. - - GNAT_ENTITY and NAME_TRAILER are used to name the resulting record and - to issue a warning. - - IS_USER_TYPE is true if we must be sure we complete the original type. - - DEFINITION is true if this type is being defined. - - SAME_RM_SIZE is true if the RM_Size of the resulting type is to be - set to its TYPE_SIZE; otherwise, it's set to the RM_Size of the original - type. */ + GNAT_ENTITY is used to name the resulting record and to issue a warning. + IS_COMPONENT_TYPE is true if this is being done for the component type + of an array. IS_USER_TYPE is true if we must complete the original type. + DEFINITION is true if this type is being defined. SAME_RM_SIZE is true + if the RM size of the resulting type is to be set to SIZE too; otherwise, + it's set to the RM size of the original type. */ extern tree maybe_pad_type (tree type, tree size, unsigned int align, - Entity_Id gnat_entity, const char *name_trailer, + Entity_Id gnat_entity, bool is_component_type, bool is_user_type, bool definition, - bool same_rm_size); + bool same_rm_size); /* Given a GNU tree and a GNAT list of choices, generate an expression to test the value passed against the list of choices. */ @@ -648,12 +643,13 @@ extern void record_global_renaming_pointer (tree decl); /* Invalidate the global renaming pointers. */ extern void invalidate_global_renaming_pointers (void); -/* Returns a FIELD_DECL node. FIELD_NAME the field name, FIELD_TYPE is its - type, and RECORD_TYPE is the type of the parent. PACKED is nonzero if - this field is in a record type with a "pragma pack". If SIZE is nonzero - it is the specified size for this field. If POS is nonzero, it is the bit - position. If ADDRESSABLE is nonzero, it means we are allowed to take - the address of this field for aliasing purposes. */ +/* Return a FIELD_DECL node. FIELD_NAME is the field's name, FIELD_TYPE is + its type and RECORD_TYPE is the type of the enclosing record. PACKED is + 1 if the enclosing record is packed, -1 if it has Component_Alignment of + Storage_Unit. If SIZE is nonzero, it is the specified size of the field. + If POS is nonzero, it is the bit position. If ADDRESSABLE is nonzero, it + means we are allowed to take the address of the field; if it is negative, + we should not make a bitfield, which is used by make_aligning_type. */ extern tree create_field_decl (tree field_name, tree field_type, tree record_type, int packed, tree size, tree pos, int addressable); diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c index 67823789ab3..570bd111a95 100644 --- a/gcc/ada/gcc-interface/misc.c +++ b/gcc/ada/gcc-interface/misc.c @@ -527,7 +527,7 @@ gnat_print_type (FILE *file, tree node, int indent) break; case RECORD_TYPE: - if (TYPE_IS_FAT_POINTER_P (node) || TYPE_CONTAINS_TEMPLATE_P (node)) + if (TYPE_FAT_POINTER_P (node) || TYPE_CONTAINS_TEMPLATE_P (node)) print_node (file, "unconstrained array", TYPE_UNCONSTRAINED_ARRAY (node), indent + 4); else @@ -600,8 +600,7 @@ static alias_set_type gnat_get_alias_set (tree type) { /* If this is a padding type, use the type of the first field. */ - if (TREE_CODE (type) == RECORD_TYPE - && TYPE_IS_PADDING_P (type)) + if (TYPE_IS_PADDING_P (type)) return get_alias_set (TREE_TYPE (TYPE_FIELDS (type))); /* If the type is an unconstrained array, use the type of the diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c index d94d1f45bfc..41be8bb77af 100644 --- a/gcc/ada/gcc-interface/trans.c +++ b/gcc/ada/gcc-interface/trans.c @@ -657,17 +657,16 @@ gigi (Node_Id gnat_root, int max_gnat_node, int number_name, error_gnat_node = Empty; } -/* Return a positive value if an lvalue is required for GNAT_NODE. - GNU_TYPE is the type that will be used for GNAT_NODE in the - translated GNU tree. CONSTANT indicates whether the underlying - object represented by GNAT_NODE is constant in the Ada sense, - ALIASED whether it is aliased (but the latter doesn't affect - the outcome if CONSTANT is not true). - - The function climbs up the GNAT tree starting from the node and - returns 1 upon encountering a node that effectively requires an - lvalue downstream. It returns int instead of bool to facilitate - usage in non purely binary logic contexts. */ +/* Return a positive value if an lvalue is required for GNAT_NODE. GNU_TYPE + is the type that will be used for GNAT_NODE in the translated GNU tree. + CONSTANT indicates whether the underlying object represented by GNAT_NODE + is constant in the Ada sense, ALIASED whether it is aliased (but the latter + doesn't affect the outcome if CONSTANT is not true). + + The function climbs up the GNAT tree starting from the node and returns 1 + upon encountering a node that effectively requires an lvalue downstream. + It returns int instead of bool to facilitate usage in non-purely binary + logic contexts. */ static int lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant, @@ -754,6 +753,13 @@ lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant, || (Is_Composite_Type (Underlying_Type (Etype (gnat_node))) && Is_Atomic (Entity (Name (gnat_parent))))); + case N_Unchecked_Type_Conversion: + /* Returning 0 is very likely correct but we get better code if we + go through the conversion. */ + return lvalue_required_p (gnat_parent, + get_unpadded_type (Etype (gnat_parent)), + constant, aliased); + default: return 0; } @@ -946,8 +952,7 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p) || Is_Constr_Subt_For_UN_Aliased (gnat_temp_type)) { gnu_result_type = TREE_TYPE (gnu_result); - if (TREE_CODE (gnu_result_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_result_type)) + if (TYPE_IS_PADDING_P (gnu_result_type)) gnu_result_type = TREE_TYPE (TYPE_FIELDS (gnu_result_type)); } @@ -1256,7 +1261,7 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) /* If this is an unconstrained array, we know the object has been allocated with the template in front of the object. So compute the template address. */ - if (TYPE_FAT_POINTER_P (TREE_TYPE (gnu_ptr))) + if (TYPE_IS_FAT_POINTER_P (TREE_TYPE (gnu_ptr))) gnu_ptr = convert (build_pointer_type (TYPE_OBJECT_RECORD_TYPE @@ -1318,29 +1323,28 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) } /* If we're looking for the size of a field, return the field size. - Otherwise, if the prefix is an object, or if 'Object_Size or - 'Max_Size_In_Storage_Elements has been specified, the result is the - GCC size of the type. Otherwise, the result is the RM size of the - type. */ + Otherwise, if the prefix is an object, or if we're looking for + 'Object_Size or 'Max_Size_In_Storage_Elements, the result is the + GCC size of the type. Otherwise, it is the RM size of the type. */ if (TREE_CODE (gnu_prefix) == COMPONENT_REF) gnu_result = DECL_SIZE (TREE_OPERAND (gnu_prefix, 1)); else if (TREE_CODE (gnu_prefix) != TYPE_DECL || attribute == Attr_Object_Size || attribute == Attr_Max_Size_In_Storage_Elements) { - /* If this is a padded type, the GCC size isn't relevant to the - programmer. Normally, what we want is the RM size, which was set - from the specified size, but if it was not set, we want the size - of the relevant field. Using the MAX of those two produces the - right result in all case. Don't use the size of the field if it's - a self-referential type, since that's never what's wanted. */ - if (TREE_CODE (gnu_type) == RECORD_TYPE + /* If the prefix is an object of a padded type, the GCC size isn't + relevant to the programmer. Normally what we want is the RM size, + which was set from the specified size, but if it was not set, we + want the size of the field. Using the MAX of those two produces + the right result in all cases. Don't use the size of the field + if it's self-referential, since that's never what's wanted. */ + if (TREE_CODE (gnu_prefix) != TYPE_DECL && TYPE_IS_PADDING_P (gnu_type) && TREE_CODE (gnu_expr) == COMPONENT_REF) { gnu_result = rm_size (gnu_type); - if (!(CONTAINS_PLACEHOLDER_P - (DECL_SIZE (TREE_OPERAND (gnu_expr, 1))))) + if (!CONTAINS_PLACEHOLDER_P + (DECL_SIZE (TREE_OPERAND (gnu_expr, 1)))) gnu_result = size_binop (MAX_EXPR, gnu_result, DECL_SIZE (TREE_OPERAND (gnu_expr, 1))); @@ -1353,7 +1357,7 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) tree gnu_ptr_type = TREE_TYPE (gnat_to_gnu (Prefix (gnat_deref))); - if (TYPE_FAT_OR_THIN_POINTER_P (gnu_ptr_type) + if (TYPE_IS_FAT_OR_THIN_POINTER_P (gnu_ptr_type) && Present (gnat_actual_subtype)) { tree gnu_actual_obj_type @@ -1403,9 +1407,7 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) unsigned int align; if (TREE_CODE (gnu_prefix) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0))) - == RECORD_TYPE) - && (TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0))))) + && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))) gnu_prefix = TREE_OPERAND (gnu_prefix, 0); gnu_type = TREE_TYPE (gnu_prefix); @@ -1742,9 +1744,7 @@ Attribute_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, int attribute) case Attr_Component_Size: if (TREE_CODE (gnu_prefix) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0))) - == RECORD_TYPE) - && (TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0))))) + && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_prefix, 0)))) gnu_prefix = TREE_OPERAND (gnu_prefix, 0); gnu_prefix = maybe_implicit_deref (gnu_prefix); @@ -2423,22 +2423,27 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) } } - /* If we are calling by supplying a pointer to a target, set up that - pointer as the first argument. Use GNU_TARGET if one was passed; - otherwise, make a target by building a variable of the maximum size - of the type. */ + /* If we are calling by supplying a pointer to a target, set up that pointer + as the first argument. Use GNU_TARGET if one was passed; otherwise, make + a target by building a variable and use the maximum size of the type if + it has self-referential size. */ if (TYPE_RETURNS_BY_TARGET_PTR_P (gnu_subprog_type)) { - tree gnu_real_ret_type + tree gnu_ret_type = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (gnu_subprog_type))); if (!gnu_target) { - tree gnu_obj_type - = maybe_pad_type (gnu_real_ret_type, - max_size (TYPE_SIZE (gnu_real_ret_type), true), - 0, Etype (Name (gnat_node)), "PAD", false, - false, false); + tree gnu_obj_type; + + if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_ret_type))) + gnu_obj_type + = maybe_pad_type (gnu_ret_type, + max_size (TYPE_SIZE (gnu_ret_type), true), + 0, Etype (Name (gnat_node)), false, false, + false, true); + else + gnu_obj_type = gnu_ret_type; /* ??? We may be about to create a static temporary if we happen to be at the global binding level. That's a regression from what @@ -2454,7 +2459,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) gnu_actual_list = tree_cons (NULL_TREE, build_unary_op (ADDR_EXPR, NULL_TREE, - unchecked_convert (gnu_real_ret_type, + unchecked_convert (gnu_ret_type, gnu_target, false)), NULL_TREE); @@ -2557,10 +2562,8 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) /* Otherwise remove unpadding from the object and reset the copy. */ else if (TREE_CODE (gnu_name) == COMPONENT_REF - && ((TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_name, 0))) - == RECORD_TYPE) - && (TYPE_IS_PADDING_P - (TREE_TYPE (TREE_OPERAND (gnu_name, 0)))))) + && TYPE_IS_PADDING_P + (TREE_TYPE (TREE_OPERAND (gnu_name, 0)))) gnu_name = gnu_copy = TREE_OPERAND (gnu_name, 0); /* Otherwise convert to the nominal type of the object if it's @@ -2599,7 +2602,6 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) /* If this was a procedure call, we may not have removed any padding. So do it here for the part we will use as an input, if any. */ if (Ekind (gnat_formal) != E_Out_Parameter - && TREE_CODE (TREE_TYPE (gnu_actual)) == RECORD_TYPE && TYPE_IS_PADDING_P (TREE_TYPE (gnu_actual))) gnu_actual = convert (get_unpadded_type (Etype (gnat_actual)), gnu_actual); @@ -2669,8 +2671,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) gnu_actual = gnu_name; /* If we have a padded type, be sure we've removed padding. */ - if (TREE_CODE (TREE_TYPE (gnu_actual)) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (gnu_actual)) + if (TYPE_IS_PADDING_P (TREE_TYPE (gnu_actual)) && TREE_CODE (gnu_actual) != SAVE_EXPR) gnu_actual = convert (get_unpadded_type (Etype (gnat_actual)), gnu_actual); @@ -2703,8 +2704,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) gnu_actual = maybe_implicit_deref (gnu_actual); gnu_actual = maybe_unconstrained_array (gnu_actual); - if (TREE_CODE (gnu_formal_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (gnu_formal_type)) + if (TYPE_IS_PADDING_P (gnu_formal_type)) { gnu_formal_type = TREE_TYPE (TYPE_FIELDS (gnu_formal_type)); gnu_actual = convert (gnu_formal_type, gnu_actual); @@ -2896,8 +2896,7 @@ call_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p, tree gnu_target) = maybe_unconstrained_array (TREE_VALUE (gnu_name_list)); /* If the result is a padded type, remove the padding. */ - if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))) + if (TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))) gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))), gnu_result); @@ -3856,8 +3855,7 @@ gnat_to_gnu (Node_Id gnat_node) gnu_array_object = maybe_unconstrained_array (gnu_array_object); /* If we got a padded type, remove it too. */ - if (TREE_CODE (TREE_TYPE (gnu_array_object)) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (gnu_array_object))) + if (TYPE_IS_PADDING_P (TREE_TYPE (gnu_array_object))) gnu_array_object = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_array_object))), gnu_array_object); @@ -4713,12 +4711,10 @@ gnat_to_gnu (Node_Id gnat_node) type is self-referential since we want to allocate the fixed size in that case. */ if (TREE_CODE (gnu_ret_val) == COMPONENT_REF - && (TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_ret_val, 0))) - == RECORD_TYPE) - && (TYPE_IS_PADDING_P - (TREE_TYPE (TREE_OPERAND (gnu_ret_val, 0)))) - && (CONTAINS_PLACEHOLDER_P - (TYPE_SIZE (TREE_TYPE (gnu_ret_val))))) + && TYPE_IS_PADDING_P + (TREE_TYPE (TREE_OPERAND (gnu_ret_val, 0))) + && CONTAINS_PLACEHOLDER_P + (TYPE_SIZE (TREE_TYPE (gnu_ret_val)))) gnu_ret_val = TREE_OPERAND (gnu_ret_val, 0); if (TYPE_RETURNS_BY_REF_P (gnu_subprog_type) @@ -5151,7 +5147,7 @@ gnat_to_gnu (Node_Id gnat_node) a fat pointer, then go back below to a thin pointer. The reason for this is that we need a fat pointer someplace in order to properly compute the size. */ - if (TYPE_THIN_POINTER_P (TREE_TYPE (gnu_ptr))) + if (TYPE_IS_THIN_POINTER_P (TREE_TYPE (gnu_ptr))) gnu_ptr = build_unary_op (ADDR_EXPR, NULL_TREE, build_unary_op (INDIRECT_REF, NULL_TREE, gnu_ptr)); @@ -5160,7 +5156,7 @@ gnat_to_gnu (Node_Id gnat_node) have been allocated with the template in front of the object. So pass the template address, but get the total size. Do this by converting to a thin pointer. */ - if (TYPE_FAT_POINTER_P (TREE_TYPE (gnu_ptr))) + if (TYPE_IS_FAT_POINTER_P (TREE_TYPE (gnu_ptr))) gnu_ptr = convert (build_pointer_type (TYPE_OBJECT_RECORD_TYPE @@ -5174,7 +5170,7 @@ gnat_to_gnu (Node_Id gnat_node) gnu_actual_obj_type = gnat_to_gnu_type (Actual_Designated_Subtype (gnat_node)); - if (TYPE_FAT_OR_THIN_POINTER_P (gnu_ptr_type)) + if (TYPE_IS_FAT_OR_THIN_POINTER_P (gnu_ptr_type)) gnu_actual_obj_type = build_unc_object_type_from_ptr (gnu_ptr_type, gnu_actual_obj_type, @@ -5286,10 +5282,10 @@ gnat_to_gnu (Node_Id gnat_node) /* But if the result is a fat pointer type, we have no mechanism to do that, so we unconditionally warn in problematic cases. */ - else if (TYPE_FAT_POINTER_P (gnu_target_type)) + else if (TYPE_IS_FAT_POINTER_P (gnu_target_type)) { tree gnu_source_array_type - = TYPE_FAT_POINTER_P (gnu_source_type) + = TYPE_IS_FAT_POINTER_P (gnu_source_type) ? TREE_TYPE (TREE_TYPE (TYPE_FIELDS (gnu_source_type))) : NULL_TREE; tree gnu_target_array_type @@ -5297,7 +5293,7 @@ gnat_to_gnu (Node_Id gnat_node) if ((TYPE_DUMMY_P (gnu_target_array_type) || get_alias_set (gnu_target_array_type) != 0) - && (!TYPE_FAT_POINTER_P (gnu_source_type) + && (!TYPE_IS_FAT_POINTER_P (gnu_source_type) || (TYPE_DUMMY_P (gnu_source_array_type) != TYPE_DUMMY_P (gnu_target_array_type)) || (TYPE_DUMMY_P (gnu_source_array_type) @@ -5438,8 +5434,7 @@ gnat_to_gnu (Node_Id gnat_node) size: in that case it must be an object of unconstrained type with a default discriminant and we want to avoid copying too much data. */ - if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)) + if (TYPE_IS_PADDING_P (TREE_TYPE (gnu_result)) && CONTAINS_PLACEHOLDER_P (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result)))))) gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))), @@ -5459,8 +5454,7 @@ gnat_to_gnu (Node_Id gnat_node) && TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE)) { /* Remove any padding. */ - if (TREE_CODE (TREE_TYPE (gnu_result)) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))) + if (TYPE_IS_PADDING_P (TREE_TYPE (gnu_result))) gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))), gnu_result); } @@ -5602,7 +5596,7 @@ add_decl_expr (tree gnu_decl, Entity_Id gnat_entity) { /* If GNU_DECL has a padded type, convert it to the unpadded type so the assignment is done properly. */ - if (TREE_CODE (type) == RECORD_TYPE && TYPE_IS_PADDING_P (type)) + if (TYPE_IS_PADDING_P (type)) t = convert (TREE_TYPE (TYPE_FIELDS (type)), gnu_decl); else t = gnu_decl; @@ -6786,8 +6780,7 @@ convert_with_check (Entity_Id gnat_type, tree gnu_expr, bool overflowp, = FP_ARITH_MAY_WIDEN ? longest_float_type_node : gnu_in_basetype; /* FIXME: Should not have padding in the first place. */ - if (TREE_CODE (calc_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (calc_type)) + if (TYPE_IS_PADDING_P (calc_type)) calc_type = TREE_TYPE (TYPE_FIELDS (calc_type)); /* Compute the exact value calc_type'Pred (0.5) at compile time. */ @@ -6962,6 +6955,10 @@ addressable_p (tree gnu_expr, tree gnu_type) case CALL_EXPR: case PLUS_EXPR: case MINUS_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case BIT_NOT_EXPR: /* All rvalues are deemed addressable since taking their address will force a temporary to be created by the middle-end. */ return true; @@ -6984,7 +6981,7 @@ addressable_p (tree gnu_expr, tree gnu_type) || DECL_ALIGN (TREE_OPERAND (gnu_expr, 1)) >= TYPE_ALIGN (TREE_TYPE (gnu_expr)))) /* The field of a padding record is always addressable. */ - || TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_expr, 0)))) + || TYPE_PADDING_P (TREE_TYPE (TREE_OPERAND (gnu_expr, 0)))) && addressable_p (TREE_OPERAND (gnu_expr, 0), NULL_TREE)); case ARRAY_REF: case ARRAY_RANGE_REF: @@ -7264,13 +7261,12 @@ static tree maybe_implicit_deref (tree exp) { /* If the type is a pointer, dereference it. */ - - if (POINTER_TYPE_P (TREE_TYPE (exp)) || TYPE_FAT_POINTER_P (TREE_TYPE (exp))) + if (POINTER_TYPE_P (TREE_TYPE (exp)) + || TYPE_IS_FAT_POINTER_P (TREE_TYPE (exp))) exp = build_unary_op (INDIRECT_REF, NULL_TREE, exp); /* If we got a padded type, remove it too. */ - if (TREE_CODE (TREE_TYPE (exp)) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (exp))) + if (TYPE_IS_PADDING_P (TREE_TYPE (exp))) exp = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (exp))), exp); return exp; @@ -7308,7 +7304,7 @@ protect_multiple_eval (tree exp) /* If this is a fat pointer or something that can be placed into a register, just make a SAVE_EXPR. */ - if (TYPE_FAT_POINTER_P (type) || TYPE_MODE (type) != BLKmode) + if (TYPE_IS_FAT_POINTER_P (type) || TYPE_MODE (type) != BLKmode) return save_expr (exp); /* Otherwise, reference, protect the address and dereference. */ @@ -7493,7 +7489,7 @@ gnat_stabilize_reference_1 (tree e, bool force) fat pointer. This may be more efficient, but will also allow us to more easily find the match for the PLACEHOLDER_EXPR. */ if (code == COMPONENT_REF - && TYPE_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0)))) + && TYPE_IS_FAT_POINTER_P (TREE_TYPE (TREE_OPERAND (e, 0)))) result = build3 (COMPONENT_REF, type, gnat_stabilize_reference_1 (TREE_OPERAND (e, 0), force), diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index 7acb2ce2de4..c79dd4e7a65 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -59,10 +59,6 @@ #include "ada-tree.h" #include "gigi.h" -#ifndef MAX_FIXED_MODE_SIZE -#define MAX_FIXED_MODE_SIZE GET_MODE_BITSIZE (DImode) -#endif - #ifndef MAX_BITS_PER_WORD #define MAX_BITS_PER_WORD BITS_PER_WORD #endif @@ -490,7 +486,7 @@ gnat_pushdecl (tree decl, Node_Id gnat_node) if (!(TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL)) ; - else if (TYPE_FAT_POINTER_P (t)) + else if (TYPE_IS_FAT_POINTER_P (t)) { tree tt = build_variant_type_copy (t); TYPE_NAME (tt) = decl; @@ -643,7 +639,7 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, if ((TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == QUAL_UNION_TYPE) - && !TYPE_IS_FAT_POINTER_P (type) + && !TYPE_FAT_POINTER_P (type) && !TYPE_CONTAINS_TEMPLATE_P (type) && TYPE_ADA_SIZE (type)) this_ada_size = TYPE_ADA_SIZE (type); @@ -739,21 +735,15 @@ finish_record_type (tree record_type, tree fieldlist, int rep_level, if (code == QUAL_UNION_TYPE) nreverse (fieldlist); - /* If the type is discriminated, it can be used to access all its - constrained subtypes, so force structural equality checks. */ - if (CONTAINS_PLACEHOLDER_P (size)) - SET_TYPE_STRUCTURAL_EQUALITY (record_type); - if (rep_level < 2) { /* If this is a padding record, we never want to make the size smaller than what was specified in it, if any. */ - if (TREE_CODE (record_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (record_type) && TYPE_SIZE (record_type)) + if (TYPE_IS_PADDING_P (record_type) && TYPE_SIZE (record_type)) size = TYPE_SIZE (record_type); /* Now set any of the values we've just computed that apply. */ - if (!TYPE_IS_FAT_POINTER_P (record_type) + if (!TYPE_FAT_POINTER_P (record_type) && !TYPE_CONTAINS_TEMPLATE_P (record_type)) SET_TYPE_ADA_SIZE (record_type, ada_size); @@ -815,9 +805,7 @@ rest_of_record_type_compilation (tree record_type) that tells the debugger how the record is laid out. See exp_dbug.ads. But don't do this for records that are padding since they confuse GDB. */ - if (var_size - && !(TREE_CODE (record_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (record_type))) + if (var_size && !TYPE_IS_PADDING_P (record_type)) { tree new_record_type = make_node (TREE_CODE (record_type) == QUAL_UNION_TYPE @@ -1306,7 +1294,7 @@ create_type_decl (tree type_name, tree type, struct attrib *attr_list, if (code == UNCONSTRAINED_ARRAY_TYPE || !debug_info_p) DECL_IGNORED_P (type_decl) = 1; else if (code != ENUMERAL_TYPE - && (code != RECORD_TYPE || TYPE_IS_FAT_POINTER_P (type)) + && (code != RECORD_TYPE || TYPE_FAT_POINTER_P (type)) && !((code == POINTER_TYPE || code == REFERENCE_TYPE) && TYPE_IS_DUMMY_P (TREE_TYPE (type))) && !(code == RECORD_TYPE @@ -1465,13 +1453,13 @@ aggregate_type_contains_array_p (tree type) } } -/* Return a FIELD_DECL node. FIELD_NAME the field name, FIELD_TYPE is its - type, and RECORD_TYPE is the type of the parent. PACKED is nonzero if - this field is in a record type with a "pragma pack". If SIZE is nonzero - it is the specified size for this field. If POS is nonzero, it is the bit - position. If ADDRESSABLE is nonzero, it means we are allowed to take - the address of this field for aliasing purposes. If it is negative, we - should not make a bitfield, which is used by make_aligning_type. */ +/* Return a FIELD_DECL node. FIELD_NAME is the field's name, FIELD_TYPE is + its type and RECORD_TYPE is the type of the enclosing record. PACKED is + 1 if the enclosing record is packed, -1 if it has Component_Alignment of + Storage_Unit. If SIZE is nonzero, it is the specified size of the field. + If POS is nonzero, it is the bit position. If ADDRESSABLE is nonzero, it + means we are allowed to take the address of the field; if it is negative, + we should not make a bitfield, which is used by make_aligning_type. */ tree create_field_decl (tree field_name, tree field_type, tree record_type, @@ -1505,12 +1493,8 @@ create_field_decl (tree field_name, tree field_type, tree record_type, else if (packed == 1) { size = rm_size (field_type); - - /* For a constant size larger than MAX_FIXED_MODE_SIZE, round up to - byte. */ - if (TREE_CODE (size) == INTEGER_CST - && compare_tree_int (size, MAX_FIXED_MODE_SIZE) > 0) - size = round_up (size, BITS_PER_UNIT); + if (TYPE_MODE (field_type) == BLKmode) + size = round_up (size, BITS_PER_UNIT); } /* If we may, according to ADDRESSABLE, make a bitfield if a size is @@ -1874,9 +1858,9 @@ create_subprog_decl (tree subprog_name, tree asm_name, to be declared as the "main" function literally by default. Ada program entry points are typically declared with a different name within the binder generated file, exported as 'main' to satisfy the - system expectations. Redirect main_identifier_node in this case. */ + system expectations. Force main_identifier_node in this case. */ if (asm_name == main_identifier_node) - main_identifier_node = DECL_NAME (subprog_decl); + DECL_NAME (subprog_decl) = main_identifier_node; } process_attributes (subprog_decl, attr_list); @@ -2193,16 +2177,28 @@ gnat_type_for_mode (enum machine_mode mode, int unsignedp) { if (mode == BLKmode) return NULL_TREE; - else if (mode == VOIDmode) + + if (mode == VOIDmode) return void_type_node; - else if (COMPLEX_MODE_P (mode)) + + if (COMPLEX_MODE_P (mode)) return NULL_TREE; - else if (SCALAR_FLOAT_MODE_P (mode)) + + if (SCALAR_FLOAT_MODE_P (mode)) return float_type_for_precision (GET_MODE_PRECISION (mode), mode); - else if (SCALAR_INT_MODE_P (mode)) + + if (SCALAR_INT_MODE_P (mode)) return gnat_type_for_size (GET_MODE_BITSIZE (mode), unsignedp); - else - return NULL_TREE; + + if (VECTOR_MODE_P (mode)) + { + enum machine_mode inner_mode = GET_MODE_INNER (mode); + tree inner_type = gnat_type_for_mode (inner_mode, unsignedp); + if (inner_type) + return build_vector_type_for_mode (inner_type, mode); + } + + return NULL_TREE; } /* Return the unsigned version of a TYPE_NODE, a scalar type. */ @@ -2291,7 +2287,7 @@ gnat_types_compatible_p (tree t1, tree t2) /* Padding record types are also compatible if they pad the same type and have the same constant size. */ if (code == RECORD_TYPE - && TYPE_IS_PADDING_P (t1) && TYPE_IS_PADDING_P (t2) + && TYPE_PADDING_P (t1) && TYPE_PADDING_P (t2) && TREE_TYPE (TYPE_FIELDS (t1)) == TREE_TYPE (TYPE_FIELDS (t2)) && tree_int_cst_equal (TYPE_SIZE (t1), TYPE_SIZE (t2))) return 1; @@ -2441,7 +2437,7 @@ build_template (tree template_type, tree array_type, tree expr) tree field; while (TREE_CODE (array_type) == RECORD_TYPE - && (TYPE_IS_PADDING_P (array_type) + && (TYPE_PADDING_P (array_type) || TYPE_JUSTIFIED_MODULAR_P (array_type))) array_type = TREE_TYPE (TYPE_FIELDS (array_type)); @@ -3155,7 +3151,7 @@ convert_vms_descriptor64 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog) if (POINTER_TYPE_P (gnu_type)) return convert (gnu_type, gnu_expr64); - else if (TYPE_FAT_POINTER_P (gnu_type)) + else if (TYPE_IS_FAT_POINTER_P (gnu_type)) { tree p_array_type = TREE_TYPE (TYPE_FIELDS (gnu_type)); tree p_bounds_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (gnu_type))); @@ -3304,7 +3300,7 @@ convert_vms_descriptor32 (tree gnu_type, tree gnu_expr, Entity_Id gnat_subprog) if (POINTER_TYPE_P (gnu_type)) return convert (gnu_type, gnu_expr32); - else if (TYPE_FAT_POINTER_P (gnu_type)) + else if (TYPE_IS_FAT_POINTER_P (gnu_type)) { tree p_array_type = TREE_TYPE (TYPE_FIELDS (gnu_type)); tree p_bounds_type = TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (gnu_type))); @@ -3542,10 +3538,10 @@ build_unc_object_type_from_ptr (tree thin_fat_ptr_type, tree object_type, { tree template_type; - gcc_assert (TYPE_FAT_OR_THIN_POINTER_P (thin_fat_ptr_type)); + gcc_assert (TYPE_IS_FAT_OR_THIN_POINTER_P (thin_fat_ptr_type)); template_type - = (TYPE_FAT_POINTER_P (thin_fat_ptr_type) + = (TYPE_IS_FAT_POINTER_P (thin_fat_ptr_type) ? TREE_TYPE (TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (thin_fat_ptr_type)))) : TREE_TYPE (TYPE_FIELDS (TREE_TYPE (thin_fat_ptr_type)))); return build_unc_object_type (template_type, object_type, name); @@ -3641,7 +3637,7 @@ update_pointer_to (tree old_type, tree new_type) /* Now deal with the unconstrained array case. In this case the "pointer" is actually a RECORD_TYPE where both fields are pointers to dummy nodes. Turn them into pointers to the correct types using update_pointer_to. */ - else if (!TYPE_FAT_POINTER_P (ptr)) + else if (!TYPE_IS_FAT_POINTER_P (ptr)) gcc_unreachable (); else @@ -3742,7 +3738,7 @@ convert_to_fat_pointer (tree type, tree expr) NULL_TREE))); /* If EXPR is a thin pointer, make template and data from the record.. */ - else if (TYPE_THIN_POINTER_P (etype)) + else if (TYPE_IS_THIN_POINTER_P (etype)) { tree fields = TYPE_FIELDS (TREE_TYPE (etype)); @@ -3792,7 +3788,7 @@ convert_to_fat_pointer (tree type, tree expr) static tree convert_to_thin_pointer (tree type, tree expr) { - if (!TYPE_FAT_POINTER_P (TREE_TYPE (expr))) + if (!TYPE_IS_FAT_POINTER_P (TREE_TYPE (expr))) expr = convert_to_fat_pointer (TREE_TYPE (TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))), expr); @@ -3827,7 +3823,7 @@ convert (tree type, tree expr) as an unchecked conversion. Likewise if one is a mere variant of the other, so we avoid a pointless unpad/repad sequence. */ else if (code == RECORD_TYPE && ecode == RECORD_TYPE - && TYPE_IS_PADDING_P (type) && TYPE_IS_PADDING_P (etype) + && TYPE_PADDING_P (type) && TYPE_PADDING_P (etype) && (!TREE_CONSTANT (TYPE_SIZE (type)) || !TREE_CONSTANT (TYPE_SIZE (etype)) || gnat_types_compatible_p (type, etype) @@ -3837,7 +3833,7 @@ convert (tree type, tree expr) /* If the output type has padding, convert to the inner type and make a constructor to build the record, unless a variable size is involved. */ - else if (code == RECORD_TYPE && TYPE_IS_PADDING_P (type)) + else if (code == RECORD_TYPE && TYPE_PADDING_P (type)) { /* If we previously converted from another type and our type is of variable size, remove the conversion to avoid the need for @@ -3855,7 +3851,6 @@ convert (tree type, tree expr) variable-sized temporaries. Likewise if the padding is a variant of the other, so we avoid a pointless unpad/repad sequence. */ if (TREE_CODE (expr) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (expr, 0))) && (!TREE_CONSTANT (TYPE_SIZE (type)) || gnat_types_compatible_p (type, @@ -3865,12 +3860,17 @@ convert (tree type, tree expr) == TYPE_NAME (TREE_TYPE (TYPE_FIELDS (type)))))) return convert (type, TREE_OPERAND (expr, 0)); - /* If the result type is a padded type with a self-referentially-sized - field and the expression type is a record, do this as an unchecked - conversion. */ + /* If the inner type is of self-referential size and the expression type + is a record, do this as an unchecked conversion. But first pad the + expression if possible to have the same size on both sides. */ if (TREE_CODE (etype) == RECORD_TYPE && CONTAINS_PLACEHOLDER_P (DECL_SIZE (TYPE_FIELDS (type)))) - return unchecked_convert (type, expr, false); + { + if (TREE_CONSTANT (TYPE_SIZE (etype))) + expr = convert (maybe_pad_type (etype, TYPE_SIZE (type), 0, Empty, + false, false, false, true), expr); + return unchecked_convert (type, expr, false); + } /* If we are converting between array types with variable size, do the final conversion as an unchecked conversion, again to avoid the need @@ -3898,7 +3898,7 @@ convert (tree type, tree expr) The conditions ordering is arranged to ensure that the output type is not a padding type here, as it is not clear whether the conversion would always be correct if this was to happen. */ - else if (ecode == RECORD_TYPE && TYPE_IS_PADDING_P (etype)) + else if (ecode == RECORD_TYPE && TYPE_PADDING_P (etype)) { tree unpadded; @@ -4147,7 +4147,8 @@ convert (tree type, tree expr) /* Otherwise, we may just bypass the input view conversion unless one of the types is a fat pointer, which is handled by specialized code below which relies on exact type matching. */ - else if (!TYPE_FAT_POINTER_P (type) && !TYPE_FAT_POINTER_P (etype)) + else if (!TYPE_IS_FAT_POINTER_P (type) + && !TYPE_IS_FAT_POINTER_P (etype)) return convert (type, op0); } } @@ -4166,7 +4167,7 @@ convert (tree type, tree expr) || TREE_CODE (type) == UNION_TYPE) && (TREE_CODE (etype) == RECORD_TYPE || TREE_CODE (etype) == UNION_TYPE) - && !TYPE_FAT_POINTER_P (type) && !TYPE_FAT_POINTER_P (etype)) + && !TYPE_IS_FAT_POINTER_P (type) && !TYPE_IS_FAT_POINTER_P (etype)) return build_unary_op (INDIRECT_REF, NULL_TREE, convert (build_pointer_type (type), TREE_OPERAND (expr, 0))); @@ -4177,7 +4178,7 @@ convert (tree type, tree expr) } /* Check for converting to a pointer to an unconstrained array. */ - if (TYPE_FAT_POINTER_P (type) && !TYPE_FAT_POINTER_P (etype)) + if (TYPE_IS_FAT_POINTER_P (type) && !TYPE_IS_FAT_POINTER_P (etype)) return convert_to_fat_pointer (type, expr); /* If we are converting between two aggregate or vector types that are mere @@ -4249,7 +4250,7 @@ convert (tree type, tree expr) /* If converting between two pointers to records denoting both a template and type, adjust if needed to account for any differing offsets, since one might be negative. */ - if (TYPE_THIN_POINTER_P (etype) && TYPE_THIN_POINTER_P (type)) + if (TYPE_IS_THIN_POINTER_P (etype) && TYPE_IS_THIN_POINTER_P (type)) { tree bit_diff = size_diffop (bit_position (TYPE_FIELDS (TREE_TYPE (etype))), @@ -4267,13 +4268,13 @@ convert (tree type, tree expr) } /* If converting to a thin pointer, handle specially. */ - if (TYPE_THIN_POINTER_P (type) + if (TYPE_IS_THIN_POINTER_P (type) && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))) return convert_to_thin_pointer (type, expr); /* If converting fat pointer to normal pointer, get the pointer to the array and then convert it. */ - else if (TYPE_FAT_POINTER_P (etype)) + else if (TYPE_IS_FAT_POINTER_P (etype)) expr = build_component_ref (expr, get_identifier ("P_ARRAY"), NULL_TREE, false); @@ -4370,8 +4371,7 @@ remove_conversions (tree exp, bool true_address) break; case COMPONENT_REF: - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (exp, 0)))) + if (TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (exp, 0)))) return remove_conversions (TREE_OPERAND (exp, 0), true_address); break; @@ -4420,7 +4420,7 @@ maybe_unconstrained_array (tree exp) case RECORD_TYPE: /* If this is a padded type, convert to the unpadded type and see if it contains a template. */ - if (TYPE_IS_PADDING_P (TREE_TYPE (exp))) + if (TYPE_PADDING_P (TREE_TYPE (exp))) { new_exp = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (exp))), exp); if (TREE_CODE (TREE_TYPE (new_exp)) == RECORD_TYPE @@ -4523,13 +4523,13 @@ unchecked_convert (tree type, tree expr, bool notrunc_p) if ((((INTEGRAL_TYPE_P (type) && !(TREE_CODE (type) == INTEGER_TYPE && TYPE_VAX_FLOATING_POINT_P (type))) - || (POINTER_TYPE_P (type) && ! TYPE_THIN_POINTER_P (type)) + || (POINTER_TYPE_P (type) && ! TYPE_IS_THIN_POINTER_P (type)) || (TREE_CODE (type) == RECORD_TYPE && TYPE_JUSTIFIED_MODULAR_P (type))) && ((INTEGRAL_TYPE_P (etype) && !(TREE_CODE (etype) == INTEGER_TYPE && TYPE_VAX_FLOATING_POINT_P (etype))) - || (POINTER_TYPE_P (etype) && !TYPE_THIN_POINTER_P (etype)) + || (POINTER_TYPE_P (etype) && !TYPE_IS_THIN_POINTER_P (etype)) || (TREE_CODE (etype) == RECORD_TYPE && TYPE_JUSTIFIED_MODULAR_P (etype)))) || TREE_CODE (type) == UNCONSTRAINED_ARRAY_TYPE) @@ -5509,7 +5509,7 @@ handle_vector_type_attribute (tree *node, tree name, tree ARG_UNUSED (args), /* Get the representative array type, possibly nested within a padding record e.g. for alignment purposes. */ - if (TREE_CODE (rep_type) == RECORD_TYPE && TYPE_IS_PADDING_P (rep_type)) + if (TYPE_IS_PADDING_P (rep_type)) rep_type = TREE_TYPE (TYPE_FIELDS (rep_type)); if (TREE_CODE (rep_type) != ARRAY_TYPE) diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c index f8a3dfbd525..7176740f453 100644 --- a/gcc/ada/gcc-interface/utils2.c +++ b/gcc/ada/gcc-interface/utils2.c @@ -654,12 +654,9 @@ build_binary_op (enum tree_code op_code, tree result_type, can convert the constructor to the inner type, to avoid putting a VIEW_CONVERT_EXPR on the LHS. But don't do so if we wouldn't have actually copied anything. */ - else if (TREE_CODE (left_type) == RECORD_TYPE - && TYPE_IS_PADDING_P (left_type) + else if (TYPE_IS_PADDING_P (left_type) && TREE_CONSTANT (TYPE_SIZE (left_type)) && ((TREE_CODE (right_operand) == COMPONENT_REF - && TREE_CODE (TREE_TYPE (TREE_OPERAND (right_operand, 0))) - == RECORD_TYPE && TYPE_IS_PADDING_P (TREE_TYPE (TREE_OPERAND (right_operand, 0))) && gnat_types_compatible_p @@ -758,6 +755,12 @@ build_binary_op (enum tree_code op_code, tree result_type, left_type = TREE_TYPE (left_operand); } + /* For a range, make sure the element type is consistent. */ + if (op_code == ARRAY_RANGE_REF + && TREE_TYPE (operation_type) != TREE_TYPE (left_type)) + operation_type = build_array_type (TREE_TYPE (left_type), + TYPE_DOMAIN (operation_type)); + /* Then convert the right operand to its base type. This will prevent unneeded sign conversions when sizetype is wider than integer. */ right_operand = convert (right_base_type, right_operand); @@ -836,8 +839,8 @@ build_binary_op (enum tree_code op_code, tree result_type, convert both operands to that type. */ if (left_base_type != right_base_type) { - if (TYPE_FAT_POINTER_P (left_base_type) - && TYPE_FAT_POINTER_P (right_base_type) + if (TYPE_IS_FAT_POINTER_P (left_base_type) + && TYPE_IS_FAT_POINTER_P (right_base_type) && TYPE_MAIN_VARIANT (left_base_type) == TYPE_MAIN_VARIANT (right_base_type)) best_type = left_base_type; @@ -872,7 +875,7 @@ build_binary_op (enum tree_code op_code, tree result_type, /* If we are comparing a fat pointer against zero, we need to just compare the data pointer. */ - else if (TYPE_FAT_POINTER_P (left_base_type) + else if (TYPE_IS_FAT_POINTER_P (left_base_type) && TREE_CODE (right_operand) == CONSTRUCTOR && integer_zerop (VEC_index (constructor_elt, CONSTRUCTOR_ELTS (right_operand), @@ -1117,11 +1120,10 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) /* If INNER is a padding type whose field has a self-referential size, convert to that inner type. We know the offset is zero and we need to have that type visible. */ - if (TREE_CODE (TREE_TYPE (inner)) == RECORD_TYPE - && TYPE_IS_PADDING_P (TREE_TYPE (inner)) - && (CONTAINS_PLACEHOLDER_P - (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS - (TREE_TYPE (inner))))))) + if (TYPE_IS_PADDING_P (TREE_TYPE (inner)) + && CONTAINS_PLACEHOLDER_P + (TYPE_SIZE (TREE_TYPE (TYPE_FIELDS + (TREE_TYPE (inner)))))) inner = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (inner))), inner); @@ -1154,13 +1156,11 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) /* If this is just a constructor for a padded record, we can just take the address of the single field and convert it to a pointer to our type. */ - if (TREE_CODE (type) == RECORD_TYPE && TYPE_IS_PADDING_P (type)) + if (TYPE_IS_PADDING_P (type)) { - result = (VEC_index (constructor_elt, - CONSTRUCTOR_ELTS (operand), - 0) - ->value); - + result = VEC_index (constructor_elt, + CONSTRUCTOR_ELTS (operand), + 0)->value; result = convert (build_pointer_type (TREE_TYPE (operand)), build_unary_op (ADDR_EXPR, NULL_TREE, result)); break; @@ -1202,8 +1202,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) /* If we are taking the address of a padded record whose field is contains a template, take the address of the template. */ - if (TREE_CODE (type) == RECORD_TYPE - && TYPE_IS_PADDING_P (type) + if (TYPE_IS_PADDING_P (type) && TREE_CODE (TREE_TYPE (TYPE_FIELDS (type))) == RECORD_TYPE && TYPE_CONTAINS_TEMPLATE_P (TREE_TYPE (TYPE_FIELDS (type)))) { @@ -1226,7 +1225,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) make up an expression to do so. This will never survive to the backend. If TYPE is a thin pointer, first convert the operand to a fat pointer. */ - if (TYPE_THIN_POINTER_P (type) + if (TYPE_IS_THIN_POINTER_P (type) && TYPE_UNCONSTRAINED_ARRAY (TREE_TYPE (type))) { operand @@ -1235,7 +1234,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) type = TREE_TYPE (operand); } - if (TYPE_FAT_POINTER_P (type)) + if (TYPE_IS_FAT_POINTER_P (type)) { result = build1 (UNCONSTRAINED_ARRAY_REF, TYPE_UNCONSTRAINED_ARRAY (type), operand); @@ -1252,7 +1251,7 @@ build_unary_op (enum tree_code op_code, tree result_type, tree operand) } side_effects - = (!TYPE_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type))); + = (!TYPE_IS_FAT_POINTER_P (type) && TYPE_VOLATILE (TREE_TYPE (type))); break; case NEGATE_EXPR: @@ -2027,7 +2026,7 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, /* If RESULT_TYPE is a fat or thin pointer, set SIZE to be the sum of the sizes of the object and its template. Allocate the whole thing and fill in the parts that are known. */ - else if (TYPE_FAT_OR_THIN_POINTER_P (result_type)) + else if (TYPE_IS_FAT_OR_THIN_POINTER_P (result_type)) { tree storage_type = build_unc_object_type_from_ptr (result_type, type, @@ -2049,10 +2048,9 @@ build_allocator (tree type, tree init, tree result_type, Entity_Id gnat_proc, gnat_proc, gnat_pool, gnat_node); storage = convert (storage_ptr_type, protect_multiple_eval (storage)); - if (TREE_CODE (type) == RECORD_TYPE && TYPE_IS_PADDING_P (type)) + if (TYPE_IS_PADDING_P (type)) { type = TREE_TYPE (TYPE_FIELDS (type)); - if (init) init = convert (type, init); } diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index e25400d09fc..4b906fe91e9 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -307,10 +307,13 @@ The GNAT Library * Ada.Strings.Wide_Unbounded.Wide_Text_IO (a-swuwti.ads):: * Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Text_IO (a-szuzti.ads):: * Ada.Text_IO.C_Streams (a-tiocst.ads):: +* Ada.Text_IO.Reset_Standard_Files (a-tirsfi.ads):: * Ada.Wide_Characters.Unicode (a-wichun.ads):: * Ada.Wide_Text_IO.C_Streams (a-wtcstr.ads):: +* Ada.Wide_Text_IO.Reset_Standard_Files (a-wrstfi.ads):: * Ada.Wide_Wide_Characters.Unicode (a-zchuni.ads):: * Ada.Wide_Wide_Text_IO.C_Streams (a-ztcstr.ads):: +* Ada.Wide_Wide_Text_IO.Reset_Standard_Files (a-zrstfi.ads):: * GNAT.Altivec (g-altive.ads):: * GNAT.Altivec.Conversions (g-altcon.ads):: * GNAT.Altivec.Vector_Operations (g-alveop.ads):: @@ -13496,10 +13499,13 @@ of GNAT, and will generate a warning message. * Ada.Strings.Wide_Unbounded.Wide_Text_IO (a-swuwti.ads):: * Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Text_IO (a-szuzti.ads):: * Ada.Text_IO.C_Streams (a-tiocst.ads):: +* Ada.Text_IO.Reset_Standard_Files (a-tirsfi.ads):: * Ada.Wide_Characters.Unicode (a-wichun.ads):: * Ada.Wide_Text_IO.C_Streams (a-wtcstr.ads):: +* Ada.Wide_Text_IO.Reset_Standard_Files (a-wrstfi.ads):: * Ada.Wide_Wide_Characters.Unicode (a-zchuni.ads):: * Ada.Wide_Wide_Text_IO.C_Streams (a-ztcstr.ads):: +* Ada.Wide_Wide_Text_IO.Reset_Standard_Files (a-zrstfi.ads):: * GNAT.Altivec (g-altive.ads):: * GNAT.Altivec.Conversions (g-altcon.ads):: * GNAT.Altivec.Vector_Operations (g-alveop.ads):: @@ -13819,6 +13825,18 @@ C streams and @code{Text_IO}. The stream identifier can be extracted from a file opened on the Ada side, and an Ada file can be constructed from a stream opened on the C side. +@node Ada.Text_IO.Reset_Standard_Files (a-tirsfi.ads) +@section @code{Ada.Text_IO.Reset_Standard_Files} (@file{a-tirsfi.ads}) +@cindex @code{Ada.Text_IO.Reset_Standard_Files} (@file{a-tirsfi.ads}) +@cindex @code{Text_IO} resetting standard files + +@noindent +This procedure is used to reset the status of the standard files used +by Ada.Text_IO. This is useful in a situation (such as a restart in an +embedded application) where the status of the files may change during +execution (for example a standard input file may be redefined to be +interactive). + @node Ada.Wide_Characters.Unicode (a-wichun.ads) @section @code{Ada.Wide_Characters.Unicode} (@file{a-wichun.ads}) @cindex @code{Ada.Wide_Characters.Unicode} (@file{a-wichun.ads}) @@ -13839,6 +13857,18 @@ C streams and @code{Wide_Text_IO}. The stream identifier can be extracted from a file opened on the Ada side, and an Ada file can be constructed from a stream opened on the C side. +@node Ada.Wide_Text_IO.Reset_Standard_Files (a-wrstfi.ads) +@section @code{Ada.Wide_Text_IO.Reset_Standard_Files} (@file{a-wrstfi.ads}) +@cindex @code{Ada.Wide_Text_IO.Reset_Standard_Files} (@file{a-wrstfi.ads}) +@cindex @code{Wide_Text_IO} resetting standard files + +@noindent +This procedure is used to reset the status of the standard files used +by Ada.Wide_Text_IO. This is useful in a situation (such as a restart in an +embedded application) where the status of the files may change during +execution (for example a standard input file may be redefined to be +interactive). + @node Ada.Wide_Wide_Characters.Unicode (a-zchuni.ads) @section @code{Ada.Wide_Wide_Characters.Unicode} (@file{a-zchuni.ads}) @cindex @code{Ada.Wide_Wide_Characters.Unicode} (@file{a-zchuni.ads}) @@ -13859,6 +13889,18 @@ C streams and @code{Wide_Wide_Text_IO}. The stream identifier can be extracted from a file opened on the Ada side, and an Ada file can be constructed from a stream opened on the C side. +@node Ada.Wide_Wide_Text_IO.Reset_Standard_Files (a-zrstfi.ads) +@section @code{Ada.Wide_Wide_Text_IO.Reset_Standard_Files} (@file{a-zrstfi.ads}) +@cindex @code{Ada.Wide_Wide_Text_IO.Reset_Standard_Files} (@file{a-zrstfi.ads}) +@cindex @code{Wide_Wide_Text_IO} resetting standard files + +@noindent +This procedure is used to reset the status of the standard files used +by Ada.Wide_Wide_Text_IO. This is useful in a situation (such as a +restart in an embedded application) where the status of the files may +change during execution (for example a standard input file may be +redefined to be interactive). + @node GNAT.Altivec (g-altive.ads) @section @code{GNAT.Altivec} (@file{g-altive.ads}) @cindex @code{GNAT.Altivec} (@file{g-altive.ads}) diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index d777f6dd099..19304a75f40 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -5268,6 +5268,19 @@ This warning can also be turned on using @option{-gnatwa}. This switch disables warnings for a @code{with} of an internal GNAT implementation unit. +@item -gnatw.i +@emph{Activate warnings on overlapping actuals.} +@cindex @option{-gnatw.i} (@command{gcc}) +This switch enables a warning on statically detectable overlapping actuals in +a subprogram call, when one of the actuals is an in-out parameter, and the +types of the actuals are not by-copy types. The warning is off by default, +and is not included under -gnatwa. + +@item -gnatw.I +@emph{Disable warnings on overlapping actuals.} +@cindex @option{-gnatw.I} (@command{gcc}) +This switch disables warnings on overlapping actuals in a call.. + @item -gnatwj @emph{Activate warnings on obsolescent features (Annex J).} @cindex @option{-gnatwj} (@command{gcc}) @@ -6433,6 +6446,10 @@ by a space. If the token preceding a left parenthesis ends with a letter or digit, then a space must separate the two tokens. +@item +if the token following a right parenthesis starts with a letter or digit, then +a space must separate the two tokens. + @item A right parenthesis must either be the first non-blank character on a line, or it must be preceded by a non-blank character. @@ -6524,8 +6541,6 @@ the exception of ORDERED_SUBPROGRAMS, UNNECESSARY_BLANK_LINES, XTRA_PARENS, and DOS_LINE_ENDINGS. In addition @end ifset - - The switch @ifclear vms @option{-gnatyN} @@ -20659,7 +20674,7 @@ Invoking @command{gnatcheck} on the command line has the form: @smallexample $ gnatcheck @ovar{switches} @{@var{filename}@} @r{[}^-files^/FILES^=@{@var{arg_list_filename}@}@r{]} - @r{[}-cargs @var{gcc_switches}@r{]} @r{[}-rules @var{rule_options}@r{]} + @r{[}-cargs @var{gcc_switches}@r{]} -rules @var{rule_options} @end smallexample @noindent @@ -20785,18 +20800,9 @@ Quiet mode. All the diagnostics about rule violations are placed in the Short format of the report file (no version information, no list of applied rules, no list of checked sources is included) -@cindex @option{^-s1^/COMPILER_STYLE^} (@command{gnatcheck}) -@item ^-s1^/COMPILER_STYLE^ -Include the compiler-style section in the report file - -@cindex @option{^-s2^/BY_RULES^} (@command{gnatcheck}) -@item ^-s2^/BY_RULES^ -Include the section containing diagnostics ordered by rules in the report file - -@cindex @option{^-s3^/BY_FILES_BY_RULES^} (@command{gnatcheck}) -@item ^-s3^/BY_FILES_BY_RULES^ -Include the section containing diagnostics ordered by files and then by rules -in the report file +@cindex @option{^--include-file=@var{file}^/INCLUDE_FILE=@var{file}^} (@command{gnatcheck}) +@item ^--include-file^/INCLUDE_FILE^ +Append the content of the specified text file to the report file @cindex @option{^-t^/TIME^} (@command{gnatcheck}) @item ^-t^/TIME^ @@ -21226,7 +21232,9 @@ This rule has no parameters. @cindex @code{Anonymous_Subtypes} rule (for @command{gnatcheck}) @noindent -Flag all uses of anonymous subtypes. A use of an anonymous subtype is +Flag all uses of anonymous subtypes (except cases when subtype indication +is a part of a record component definition, and this subtype indication +depends on a discriminant). A use of an anonymous subtype is any instance of a subtype indication with a constraint, other than one that occurs immediately within a subtype declaration. Any use of a range other than as a constraint used immediately within a subtype declaration diff --git a/gcc/ada/gnatbind.adb b/gcc/ada/gnatbind.adb index 48eceb0ff77..fb3dc3d74ba 100644 --- a/gcc/ada/gnatbind.adb +++ b/gcc/ada/gnatbind.adb @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2008, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2009, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -838,6 +838,28 @@ begin end if; end loop; + -- Subunits do not appear in the elaboration table because they + -- are subsumed by their parent units, but we need to list them + -- for other tools. For now they are listed after other files, + -- rather than right after their parent, since there is no easy + -- link between the elaboration table and the ALIs table ??? + -- Note also that subunits may appear repeatedly in the list, + -- if the parent unit appears in the context of several units + -- in the closure. + + for J in Sdep.First .. Sdep.Last loop + if Sdep.Table (J).Subunit_Name /= No_Name + and then not Is_Internal_File_Name (Sdep.Table (J).Sfile) + then + if not Zero_Formatting then + Write_Str (" "); + end if; + + Write_Str (Get_Name_String (Sdep.Table (J).Sfile)); + Write_Eol; + end if; + end loop; + if not Zero_Formatting then Write_Eol; end if; diff --git a/gcc/ada/gnatcmd.adb b/gcc/ada/gnatcmd.adb index 563b92d150e..e0ccc228473 100644 --- a/gcc/ada/gnatcmd.adb +++ b/gcc/ada/gnatcmd.adb @@ -1612,6 +1612,7 @@ begin elsif Argv.all = "-eL" then Follow_Links_For_Files := True; + Follow_Links_For_Dirs := True; Remove_Switch (Arg_Num); diff --git a/gcc/ada/gnatlink.adb b/gcc/ada/gnatlink.adb index eb255d9fc08..5347269be00 100644 --- a/gcc/ada/gnatlink.adb +++ b/gcc/ada/gnatlink.adb @@ -189,6 +189,13 @@ procedure Gnatlink is Object_List_File_Required : Boolean := False; -- Set to True to force generation of a response file + Shared_Libgcc_Default : Character; + for Shared_Libgcc_Default'Size use Character'Size; + pragma Import + (C, Shared_Libgcc_Default, "__gnat_shared_libgcc_default"); + -- Indicates wether libgcc should be statically linked (use 'T') or + -- dynamically linked (use 'H') by default. + function Base_Name (File_Name : String) return String; -- Return just the file name part without the extension (if present) @@ -2141,11 +2148,15 @@ begin if Linker_Path = Gcc_Path and then VM_Target = No_VM then - -- If gcc is not called with -shared-libgcc, call it with - -- -static-libgcc, as there are some platforms where one of - -- these two switches is compulsory to link. + -- For systems where the default is to link statically + -- with libgcc, if gcc is not called with + -- -shared-libgcc, call it with -static-libgcc, as + -- there are some platforms where one of these two + -- switches is compulsory to link. - if not Shared_Libgcc_Seen then + if Shared_Libgcc_Default = 'T' + and then not Shared_Libgcc_Seen + then Linker_Options.Increment_Last; Linker_Options.Table (Linker_Options.Last) := Static_Libgcc; Num_Args := Num_Args + 1; diff --git a/gcc/ada/gnatname.adb b/gcc/ada/gnatname.adb index 4c6d00bd99e..4c935bebbc7 100644 --- a/gcc/ada/gnatname.adb +++ b/gcc/ada/gnatname.adb @@ -385,6 +385,7 @@ procedure Gnatname is elsif Arg = "-eL" then Opt.Follow_Links_For_Files := True; + Opt.Follow_Links_For_Dirs := True; -- -f diff --git a/gcc/ada/init.c b/gcc/ada/init.c index 5fe46cd0ff2..f9bcf634e53 100644 --- a/gcc/ada/init.c +++ b/gcc/ada/init.c @@ -2114,6 +2114,7 @@ __gnat_install_handler(void) #elif defined(__APPLE__) #include +#include #include #include #include @@ -2123,9 +2124,9 @@ char __gnat_alternate_stack[32 * 1024]; /* 1 * MINSIGSTKSZ */ static void __gnat_error_handler (int sig, siginfo_t * si, void * uc); -/* Defined in xnu unix_signal.c */ +/* Defined in xnu unix_signal.c. + Tell the kernel to re-use alt stack when delivering a signal. */ #define UC_RESET_ALT_STACK 0x80000000 -extern int sigreturn (void *uc, int flavour); /* Return true if ADDR is within a stack guard area. */ static int @@ -2173,8 +2174,9 @@ __gnat_error_handler (int sig, siginfo_t * si, void * uc ATTRIBUTE_UNUSED) msg = "erroneous memory access"; } /* Reset the use of alt stack, so that the alt stack will be used - for the next signal delivery. */ - sigreturn (NULL, UC_RESET_ALT_STACK); + for the next signal delivery. + The stack can't be used in case of stack checking. */ + syscall (SYS_sigreturn, NULL, UC_RESET_ALT_STACK); break; case SIGFPE: @@ -2301,8 +2303,10 @@ __gnat_adjust_context_for_raise (int signo ATTRIBUTE_UNUSED, { /* We used to compensate here for the raised from call vs raised from signal exception discrepancy with the GCC ZCX scheme, but this now can be dealt - with generically in the unwinder (see GCC PR other/26208). Only the VMS - ports still do the compensation described in the few lines below. + with generically in the unwinder (see GCC PR other/26208). This however + requires the use of the _Unwind_GetIPInfo routine in raise-gcc.c, which + is predicated on the definition of HAVE_GETIPINFO at compile time. Only + the VMS ports still do the compensation described in the few lines below. *** Call vs signal exception discrepancy with GCC ZCX scheme *** diff --git a/gcc/ada/link.c b/gcc/ada/link.c index c36d8e78a42..6ebd329612f 100644 --- a/gcc/ada/link.c +++ b/gcc/ada/link.c @@ -62,6 +62,9 @@ /* shared_libgnat_default gives the system dependent link method that */ /* be used by default for linking libgnat (shared or static) */ +/* shared_libgcc_default gives the system dependent link method that */ +/* be used by default for linking libgcc (shared or statis) */ + /* using_gnu_linker is set to 1 when the GNU linker is used under this */ /* target. */ @@ -89,6 +92,7 @@ const char *__gnat_run_path_option = "-Wl,-rpath,"; int __gnat_link_max = 10000; unsigned char __gnat_objlist_file_supported = 1; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; unsigned char __gnat_using_gnu_linker = 0; const char *__gnat_object_library_extension = ".a"; unsigned char __gnat_separate_run_path_options = 0; @@ -99,6 +103,7 @@ const char *__gnat_run_path_option = "-Wl,-rpath,"; int __gnat_link_max = 5000; unsigned char __gnat_objlist_file_supported = 1; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; unsigned char __gnat_using_gnu_linker = 0; const char *__gnat_object_library_extension = ".a"; unsigned char __gnat_separate_run_path_options = 0; @@ -109,6 +114,7 @@ const char *__gnat_run_path_option = ""; int __gnat_link_max = 30000; unsigned char __gnat_objlist_file_supported = 1; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; unsigned char __gnat_using_gnu_linker = 1; const char *__gnat_object_library_extension = ".a"; unsigned char __gnat_separate_run_path_options = 0; @@ -119,6 +125,7 @@ const char *__gnat_run_path_option = "-Wl,+b,"; int __gnat_link_max = 5000; unsigned char __gnat_objlist_file_supported = 1; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; unsigned char __gnat_using_gnu_linker = 0; const char *__gnat_object_library_extension = ".a"; unsigned char __gnat_separate_run_path_options = 0; @@ -129,6 +136,7 @@ const char *__gnat_run_path_option = ""; int __gnat_link_max = 15000; const unsigned char __gnat_objlist_file_supported = 1; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; unsigned char __gnat_using_gnu_linker = 0; const char *__gnat_object_library_extension = ".a"; unsigned char __gnat_separate_run_path_options = 0; @@ -137,6 +145,7 @@ unsigned char __gnat_separate_run_path_options = 0; const char *__gnat_object_file_option = ""; const char *__gnat_run_path_option = ""; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; int __gnat_link_max = 2147483647; unsigned char __gnat_objlist_file_supported = 0; unsigned char __gnat_using_gnu_linker = 0; @@ -147,6 +156,7 @@ unsigned char __gnat_separate_run_path_options = 0; const char *__gnat_object_file_option = ""; const char *__gnat_run_path_option = "-Wl,-R"; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; int __gnat_link_max = 2147483647; unsigned char __gnat_objlist_file_supported = 0; unsigned char __gnat_using_gnu_linker = 0; @@ -157,6 +167,7 @@ unsigned char __gnat_separate_run_path_options = 0; const char *__gnat_object_file_option = ""; const char *__gnat_run_path_option = "-Wl,-rpath,"; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; int __gnat_link_max = 8192; unsigned char __gnat_objlist_file_supported = 1; unsigned char __gnat_using_gnu_linker = 1; @@ -167,6 +178,7 @@ unsigned char __gnat_separate_run_path_options = 0; const char *__gnat_object_file_option = "-Wl,-filelist,"; const char *__gnat_run_path_option = "-Wl,-rpath,"; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = SHARED; int __gnat_link_max = 262144; unsigned char __gnat_objlist_file_supported = 1; unsigned char __gnat_using_gnu_linker = 0; @@ -177,6 +189,7 @@ unsigned char __gnat_separate_run_path_options = 1; const char *__gnat_object_file_option = ""; const char *__gnat_run_path_option = "-Wl,-rpath,"; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; int __gnat_link_max = 8192; unsigned char __gnat_objlist_file_supported = 1; unsigned char __gnat_using_gnu_linker = 1; @@ -187,6 +200,7 @@ unsigned char __gnat_separate_run_path_options = 0; const char *__gnat_object_file_option = ""; const char *__gnat_run_path_option = ""; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; int __gnat_link_max = 2147483647; unsigned char __gnat_objlist_file_supported = 0; unsigned char __gnat_using_gnu_linker = 0; @@ -200,6 +214,7 @@ unsigned char __gnat_separate_run_path_options = 0; const char *__gnat_run_path_option = ""; const char *__gnat_object_file_option = ""; char __gnat_shared_libgnat_default = STATIC; +char __gnat_shared_libgcc_default = STATIC; int __gnat_link_max = 2147483647; unsigned char __gnat_objlist_file_supported = 0; unsigned char __gnat_using_gnu_linker = 0; diff --git a/gcc/ada/make.adb b/gcc/ada/make.adb index dacf290c273..12e6386d045 100644 --- a/gcc/ada/make.adb +++ b/gcc/ada/make.adb @@ -106,13 +106,17 @@ package body Make is Full_Source_File : File_Name_Type; Lib_File : File_Name_Type; Source_Unit : Unit_Name_Type; + Full_Lib_File : File_Name_Type; + Lib_File_Attr : aliased File_Attributes; Mapping_File : Natural := No_Mapping_File; Project : Project_Id := No_Project; - Syntax_Only : Boolean := False; - Output_Is_Object : Boolean := True; end record; -- Data recorded for each compilation process spawned + No_Compilation_Data : constant Compilation_Data := + (Invalid_Pid, No_File, No_File, No_Unit_Name, No_File, Unknown_Attributes, + No_Mapping_File, No_Project); + type Comp_Data_Arr is array (Positive range <>) of Compilation_Data; type Comp_Data_Ptr is access Comp_Data_Arr; Running_Compile : Comp_Data_Ptr; @@ -356,7 +360,7 @@ package body Make is Project_Of_Current_Object_Directory : Project_Id := No_Project; -- The object directory of the project for the last compilation. Avoid -- calling Change_Dir if the current working directory is already this - -- directory + -- directory. -- Packages of project files where unknown attributes are errors @@ -740,6 +744,8 @@ package body Make is Is_Main_Source : Boolean; The_Args : Argument_List; Lib_File : File_Name_Type; + Full_Lib_File : File_Name_Type; + Lib_File_Attr : access File_Attributes; Read_Only : Boolean; ALI : out ALI_Id; O_File : out File_Name_Type; @@ -750,6 +756,10 @@ package body Make is -- ALI is the ALI_Id corresponding to Lib_File. If Lib_File in not -- up-to-date, then the corresponding source file needs to be recompiled. -- In this case ALI = No_ALI_Id. + -- Full_Lib_File must be the result of calling Osint.Full_Lib_File_Name on + -- Lib_File. Precomputing it saves system calls. Lib_File_Attr is the + -- initialized attributes of that file, which is also used to save on + -- system calls (it can safely be initialized to Unknown_Attributes). procedure Check_Linker_Options (E_Stamp : Time_Stamp_Type; @@ -1414,6 +1424,8 @@ package body Make is Is_Main_Source : Boolean; The_Args : Argument_List; Lib_File : File_Name_Type; + Full_Lib_File : File_Name_Type; + Lib_File_Attr : access File_Attributes; Read_Only : Boolean; ALI : out ALI_Id; O_File : out File_Name_Type; @@ -1523,9 +1535,6 @@ package body Make is -- Data declarations for Check -- --------------------------------- - Full_Lib_File : File_Name_Type; - -- Full name of current library file - Full_Obj_File : File_Name_Type; -- Full name of the object file corresponding to Lib_File @@ -1576,15 +1585,14 @@ package body Make is Check_Object_Consistency; begin Check_Object_Consistency := False; - Text := Read_Library_Info (Lib_File); + Text := Read_Library_Info_From_Full (Full_Lib_File, Lib_File_Attr); Check_Object_Consistency := Saved_Check_Object_Consistency; end; else - Text := Read_Library_Info (Lib_File); + Text := Read_Library_Info_From_Full (Full_Lib_File, Lib_File_Attr); end if; - Full_Lib_File := Full_Library_Info_Name; Full_Obj_File := Full_Object_File_Name; Lib_Stamp := Current_Library_File_Stamp; Obj_Stamp := Current_Object_File_Stamp; @@ -1858,7 +1866,8 @@ package body Make is Normalize_Pathname (Dir_Name (Get_Name_String (Full_Lib_File)), - Resolve_Links => True, + Resolve_Links => + Opt.Follow_Links_For_Dirs, Case_Sensitive => False); begin @@ -2418,62 +2427,22 @@ package body Make is Initialize_ALI_Data : Boolean := True; Max_Process : Positive := 1) is - Source_Unit : Unit_Name_Type; - -- Current source unit - - Source_File : File_Name_Type; - -- Current source file - - Full_Source_File : File_Name_Type; - -- Full name of the current source file - - Lib_File : File_Name_Type; - -- Current library file - - Full_Lib_File : File_Name_Type; - -- Full name of the current library file - - Obj_File : File_Name_Type; - -- Full name of the object file corresponding to Lib_File - - Obj_Stamp : Time_Stamp_Type; - -- Time stamp of the current object file - - Sfile : File_Name_Type; - -- Contains the source file of the units withed by Source_File - - Uname : Unit_Name_Type; - -- Contains the unit name of the units withed by Source_File - - ALI : ALI_Id; - -- ALI Id of the current ALI file - - -- Comment following declarations ??? - - Read_Only : Boolean := False; - - Compilation_OK : Boolean; - Need_To_Compile : Boolean; - - Pid : Process_Id; - Text : Text_Buffer_Ptr; - - Mfile : Natural := No_Mapping_File; + Mfile : Natural := No_Mapping_File; + Mapping_File_Arg : String_Access; + -- Info on the mapping file Need_To_Check_Standard_Library : Boolean := Check_Readonly_Files and not Unique_Compile; - Mapping_File_Arg : String_Access; - - Process_Created : Boolean := False; - procedure Add_Process - (Pid : Process_Id; - Sfile : File_Name_Type; - Afile : File_Name_Type; - Uname : Unit_Name_Type; - Mfile : Natural := No_Mapping_File); + (Pid : Process_Id; + Sfile : File_Name_Type; + Afile : File_Name_Type; + Uname : Unit_Name_Type; + Full_Lib_File : File_Name_Type; + Lib_File_Attr : File_Attributes; + Mfile : Natural := No_Mapping_File); -- Adds process Pid to the current list of outstanding compilation -- processes and record the full name of the source file Sfile that -- we are compiling, the name of its library file Afile and the @@ -2482,18 +2451,16 @@ package body Make is -- array The_Mapping_File_Names. procedure Await_Compile - (Sfile : out File_Name_Type; - Afile : out File_Name_Type; - Uname : out Unit_Name_Type; + (Data : out Compilation_Data; OK : out Boolean); -- Awaits that an outstanding compilation process terminates. When - -- it does set Sfile to the name of the source file that was compiled - -- Afile to the name of its library file and Uname to the name of its - -- unit. Note that this time stamp can be used to check whether the + -- it does set Data to the information registered for the corresponding + -- call to Add_Process. + -- Note that this time stamp can be used to check whether the -- compilation did generate an object file. OK is set to True if the - -- compilation succeeded. Note that Sfile, Afile and Uname could be - -- resp. No_File, No_File and No_Name if there were no compilations - -- to wait for. + -- compilation succeeded. + -- Data could be No_Compilation_Data if there was no compilation to wait + -- for. function Bad_Compilation_Count return Natural; -- Returns the number of compilation failures @@ -2501,8 +2468,15 @@ package body Make is procedure Check_Standard_Library; -- Check if s-stalib.adb needs to be compiled - procedure Collect_Arguments_And_Compile (Source_Index : Int); - -- Collect arguments from project file (if any) and compile + procedure Collect_Arguments_And_Compile + (Full_Source_File : File_Name_Type; + Lib_File : File_Name_Type; + Source_Index : Int; + Pid : out Process_Id; + Process_Created : out Boolean); + -- Collect arguments from project file (if any) and compile. + -- If no compilation was attempted, Processed_Created is set to False, + -- and the value of Pid is unknown. function Compile (Project : Project_Id; @@ -2545,16 +2519,41 @@ package body Make is procedure Record_Good_ALI (A : ALI_Id); -- Records in the previous set the Id of an ALI file + function Must_Exit_Because_Of_Error return Boolean; + -- Return True if there were errors and the user decided to exit in such + -- a case. This waits for any outstanding compilation. + + function Start_Compile_If_Possible (Args : Argument_List) return Boolean; + -- Check if there is more work that we can do (i.e. the Queue is non + -- empty). If there is, do it only if we have not yet used up all the + -- available processes. + -- Returns True if we should exit the main loop + + procedure Wait_For_Available_Slot; + -- Check if we should wait for a compilation to finish. This is the case + -- if all the available processes are busy compiling sources or there is + -- nothing else to do (that is the Q is empty and there are no good ALIs + -- to process). + + procedure Fill_Queue_From_ALI_Files; + -- Check if we recorded good ALI files. If yes process them now in the + -- order in which they have been recorded. There are two occasions in + -- which we record good ali files. The first is in phase 1 when, after + -- scanning an existing ALI file we realize it is up-to-date, the second + -- instance is after a successful compilation. + ----------------- -- Add_Process -- ----------------- procedure Add_Process - (Pid : Process_Id; - Sfile : File_Name_Type; - Afile : File_Name_Type; - Uname : Unit_Name_Type; - Mfile : Natural := No_Mapping_File) + (Pid : Process_Id; + Sfile : File_Name_Type; + Afile : File_Name_Type; + Uname : Unit_Name_Type; + Full_Lib_File : File_Name_Type; + Lib_File_Attr : File_Attributes; + Mfile : Natural := No_Mapping_File) is OC1 : constant Positive := Outstanding_Compiles + 1; @@ -2562,14 +2561,15 @@ package body Make is pragma Assert (OC1 <= Max_Process); pragma Assert (Pid /= Invalid_Pid); - Running_Compile (OC1).Pid := Pid; - Running_Compile (OC1).Full_Source_File := Sfile; - Running_Compile (OC1).Lib_File := Afile; - Running_Compile (OC1).Source_Unit := Uname; - Running_Compile (OC1).Mapping_File := Mfile; - Running_Compile (OC1).Project := Arguments_Project; - Running_Compile (OC1).Syntax_Only := Syntax_Only; - Running_Compile (OC1).Output_Is_Object := Output_Is_Object; + Running_Compile (OC1) := + (Pid => Pid, + Full_Source_File => Sfile, + Lib_File => Afile, + Full_Lib_File => Full_Lib_File, + Lib_File_Attr => Lib_File_Attr, + Source_Unit => Uname, + Mapping_File => Mfile, + Project => Arguments_Project); Outstanding_Compiles := OC1; end Add_Process; @@ -2579,21 +2579,17 @@ package body Make is ------------------- procedure Await_Compile - (Sfile : out File_Name_Type; - Afile : out File_Name_Type; - Uname : out Unit_Name_Type; - OK : out Boolean) + (Data : out Compilation_Data; + OK : out Boolean) is Pid : Process_Id; Project : Project_Id; - Data : Project_Compilation_Access; + Comp_Data : Project_Compilation_Access; begin pragma Assert (Outstanding_Compiles > 0); - Sfile := No_File; - Afile := No_File; - Uname := No_Unit_Name; + Data := No_Compilation_Data; OK := False; -- The loop here is a work-around for a problem on VMS; in some @@ -2611,21 +2607,19 @@ package body Make is for J in Running_Compile'First .. Outstanding_Compiles loop if Pid = Running_Compile (J).Pid then - Sfile := Running_Compile (J).Full_Source_File; - Afile := Running_Compile (J).Lib_File; - Uname := Running_Compile (J).Source_Unit; - Syntax_Only := Running_Compile (J).Syntax_Only; - Output_Is_Object := Running_Compile (J).Output_Is_Object; + Data := Running_Compile (J); Project := Running_Compile (J).Project; - -- If a mapping file was used by this compilation, - -- get its file name for reuse by a subsequent compilation + -- If a mapping file was used by this compilation, get its + -- file name for reuse by a subsequent compilation. if Running_Compile (J).Mapping_File /= No_Mapping_File then - Data := Project_Compilation_Htable.Get + Comp_Data := Project_Compilation_Htable.Get (Project_Compilation, Project); - Data.Last_Free_Indices := Data.Last_Free_Indices + 1; - Data.Free_Mapping_File_Indices (Data.Last_Free_Indices) := + Comp_Data.Last_Free_Indices := + Comp_Data.Last_Free_Indices + 1; + Comp_Data.Free_Mapping_File_Indices + (Comp_Data.Last_Free_Indices) := Running_Compile (J).Mapping_File; end if; @@ -2707,11 +2701,13 @@ package body Make is -- Collect_Arguments_And_Compile -- ----------------------------------- - procedure Collect_Arguments_And_Compile (Source_Index : Int) is + procedure Collect_Arguments_And_Compile + (Full_Source_File : File_Name_Type; + Lib_File : File_Name_Type; + Source_Index : Int; + Pid : out Process_Id; + Process_Created : out Boolean) is begin - -- Process_Created will be set True if an attempt is made to compile - -- the source, that is if it is not in an externally built project. - Process_Created := False; -- If we use mapping file (-P or -C switches), then get one @@ -2759,11 +2755,11 @@ package body Make is Pid := Compile - (Arguments_Project, - File_Name_Type (Arguments_Path_Name), - Lib_File, - Source_Index, - Arguments (1 .. Last_Argument)); + (Project => Arguments_Project, + S => File_Name_Type (Arguments_Path_Name), + L => Lib_File, + Source_Index => Source_Index, + Args => Arguments (1 .. Last_Argument)); Process_Created := True; end if; @@ -2773,11 +2769,11 @@ package body Make is Pid := Compile - (Main_Project, - Full_Source_File, - Lib_File, - Source_Index, - Arguments (1 .. Last_Argument)); + (Project => Main_Project, + S => Full_Source_File, + L => Lib_File, + Source_Index => Source_Index, + Args => Arguments (1 .. Last_Argument)); Process_Created := True; end if; end Collect_Arguments_And_Compile; @@ -2994,6 +2990,119 @@ package body Make is (Gcc_Path.all, Comp_Args (Args'First .. Comp_Last)); end Compile; + ------------------------------- + -- Fill_Queue_From_ALI_Files -- + ------------------------------- + + procedure Fill_Queue_From_ALI_Files is + ALI : ALI_Id; + Source_Index : Int; + Sfile : File_Name_Type; + Uname : Unit_Name_Type; + Unit_Name : Name_Id; + Uid : Prj.Unit_Index; + begin + while Good_ALI_Present loop + ALI := Get_Next_Good_ALI; + Source_Index := Unit_Index_Of (ALIs.Table (ALI).Afile); + + -- If we are processing the library file corresponding to the + -- main source file check if this source can be a main unit. + + if ALIs.Table (ALI).Sfile = Main_Source + and then Source_Index = Main_Index + then + Main_Unit := ALIs.Table (ALI).Main_Program /= None; + end if; + + -- The following adds the standard library (s-stalib) to the + -- list of files to be handled by gnatmake: this file and any + -- files it depends on are always included in every bind, + -- even if they are not in the explicit dependency list. + -- Of course, it is not added if Suppress_Standard_Library + -- is True. + + -- However, to avoid annoying output about s-stalib.ali being + -- read only, when "-v" is used, we add the standard library + -- only when "-a" is used. + + if Need_To_Check_Standard_Library then + Check_Standard_Library; + end if; + + -- Now insert in the Q the unmarked source files (i.e. those + -- which have never been inserted in the Q and hence never + -- considered). Only do that if Unique_Compile is False. + + if not Unique_Compile then + for J in + ALIs.Table (ALI).First_Unit .. ALIs.Table (ALI).Last_Unit + loop + for K in + Units.Table (J).First_With .. Units.Table (J).Last_With + loop + Sfile := Withs.Table (K).Sfile; + Uname := Withs.Table (K).Uname; + + -- If project files are used, find the proper source + -- to compile, in case Sfile is the spec, but there + -- is a body. + + if Main_Project /= No_Project then + Get_Name_String (Uname); + Name_Len := Name_Len - 2; + Unit_Name := Name_Find; + Uid := + Units_Htable.Get (Project_Tree.Units_HT, Unit_Name); + + if Uid /= Prj.No_Unit_Index then + if Uid.File_Names (Impl) /= null + and then not Uid.File_Names (Impl).Locally_Removed + then + Sfile := Uid.File_Names (Impl).File; + Source_Index := Uid.File_Names (Impl).Index; + + elsif Uid.File_Names (Spec) /= null + and then not Uid.File_Names (Spec).Locally_Removed + then + Sfile := Uid.File_Names (Spec).File; + Source_Index := Uid.File_Names (Spec).Index; + end if; + end if; + end if; + + Dependencies.Append ((ALIs.Table (ALI).Sfile, Sfile)); + + if Is_In_Obsoleted (Sfile) then + Executable_Obsolete := True; + end if; + + if Sfile = No_File then + Debug_Msg ("Skipping generic:", Withs.Table (K).Uname); + + else + Source_Index := Unit_Index_Of (Withs.Table (K).Afile); + + if Is_Marked (Sfile, Source_Index) then + Debug_Msg ("Skipping marked file:", Sfile); + + elsif not Check_Readonly_Files + and then Is_Internal_File_Name (Sfile, False) + then + Debug_Msg ("Skipping internal file:", Sfile); + + else + Insert_Q + (Sfile, Withs.Table (K).Uname, Source_Index); + Mark (Sfile, Source_Index); + end if; + end if; + end loop; + end loop; + end if; + end loop; + end Fill_Queue_From_ALI_Files; + ---------------------- -- Get_Mapping_File -- ---------------------- @@ -3049,6 +3158,29 @@ package body Make is return Good_ALI.First <= Good_ALI.Last; end Good_ALI_Present; + -------------------------------- + -- Must_Exit_Because_Of_Error -- + -------------------------------- + + function Must_Exit_Because_Of_Error return Boolean is + Data : Compilation_Data; + Success : Boolean; + begin + if Bad_Compilation_Count > 0 and then not Keep_Going then + while Outstanding_Compiles > 0 loop + Await_Compile (Data, Success); + + if not Success then + Record_Failure (Data.Full_Source_File, Data.Source_Unit); + end if; + end loop; + + return True; + end if; + + return False; + end Must_Exit_Because_Of_Error; + -------------------- -- Record_Failure -- -------------------- @@ -3073,276 +3205,320 @@ package body Make is Good_ALI.Table (Good_ALI.Last) := A; end Record_Good_ALI; - -- Start of processing for Compile_Sources - - begin - pragma Assert (Args'First = 1); - - Outstanding_Compiles := 0; - Running_Compile := new Comp_Data_Arr (1 .. Max_Process); - - -- Package and Queue initializations - - Good_ALI.Init; - - if First_Q_Initialization then - Init_Q; - end if; + ------------------------------- + -- Start_Compile_If_Possible -- + ------------------------------- - if Initialize_ALI_Data then - Initialize_ALI; - Initialize_ALI_Source; - end if; + function Start_Compile_If_Possible + (Args : Argument_List) return Boolean + is + In_Lib_Dir : Boolean; + Need_To_Compile : Boolean; + Pid : Process_Id; + Process_Created : Boolean; + + Source_File : File_Name_Type; + Full_Source_File : File_Name_Type; + Source_File_Attr : aliased File_Attributes; + -- The full name of the source file and its attributes (size, ...) + + Source_Unit : Unit_Name_Type; + Source_Index : Int; + -- Index of the current unit in the current source file + + Lib_File : File_Name_Type; + Full_Lib_File : File_Name_Type; + Lib_File_Attr : aliased File_Attributes; + Read_Only : Boolean := False; + ALI : ALI_Id; + -- The ALI file and its attributes (size, stamp, ...) + + Obj_File : File_Name_Type; + Obj_Stamp : Time_Stamp_Type; + -- The object file - -- The following two flags affect the behavior of ALI.Set_Source_Table. - -- We set Check_Source_Files to True to ensure that source file - -- time stamps are checked, and we set All_Sources to False to - -- avoid checking the presence of the source files listed in the - -- source dependency section of an ali file (which would be a mistake - -- since the ali file may be obsolete). + begin + if not Empty_Q and then Outstanding_Compiles < Max_Process then + Extract_From_Q (Source_File, Source_Unit, Source_Index); - Check_Source_Files := True; - All_Sources := False; + Osint.Full_Source_Name + (Source_File, + Full_File => Full_Source_File, + Attr => Source_File_Attr'Access); - -- Only insert in the Q if it is not already done, to avoid simultaneous - -- compilations if -jnnn is used. + Lib_File := Osint.Lib_File_Name (Source_File, Source_Index); + Osint.Full_Lib_File_Name + (Lib_File, + Lib_File => Full_Lib_File, + Attr => Lib_File_Attr); - if not Is_Marked (Main_Source, Main_Index) then - Insert_Q (Main_Source, Index => Main_Index); - Mark (Main_Source, Main_Index); - end if; + -- If this source has already been compiled, the executable is + -- obsolete. - First_Compiled_File := No_File; - Most_Recent_Obj_File := No_File; - Most_Recent_Obj_Stamp := Empty_Time_Stamp; - Main_Unit := False; + if Is_In_Obsoleted (Source_File) then + Executable_Obsolete := True; + end if; - -- Keep looping until there is no more work to do (the Q is empty) - -- and all the outstanding compilations have terminated + In_Lib_Dir := Full_Lib_File /= No_File + and then In_Ada_Lib_Dir (Full_Lib_File); - Make_Loop : while not Empty_Q or else Outstanding_Compiles > 0 loop + -- Since the following requires a system call, we precompute it + -- when needed. - -- If the user does not want to keep going in case of errors then - -- wait for the remaining outstanding compiles and then exit. + if not In_Lib_Dir then + if Full_Lib_File /= No_File + and then not Check_Readonly_Files + then + Get_Name_String (Full_Lib_File); + Name_Buffer (Name_Len + 1) := ASCII.NUL; + Read_Only := not Is_Writable_File + (Name_Buffer'Address, Lib_File_Attr'Access); + else + Read_Only := False; + end if; + end if; - if Bad_Compilation_Count > 0 and then not Keep_Going then - while Outstanding_Compiles > 0 loop - Await_Compile - (Full_Source_File, Lib_File, Source_Unit, Compilation_OK); + -- If the library file is an Ada library skip it - if not Compilation_OK then - Record_Failure (Full_Source_File, Source_Unit); - end if; - end loop; + if In_Lib_Dir then + Verbose_Msg + (Lib_File, + "is in an Ada library", + Prefix => " ", + Minimum_Verbosity => Opt.High); - exit Make_Loop; - end if; + -- If the library file is a read-only library skip it, but only + -- if, when using project files, this library file is in the + -- right object directory (a read-only ALI file in the object + -- directory of a project being extended must not be skipped). - -- PHASE 1: Check if there is more work that we can do (i.e. the Q - -- is non empty). If there is, do it only if we have not yet used - -- up all the available processes. + elsif Read_Only + and then Is_In_Object_Directory (Source_File, Full_Lib_File) + then + Verbose_Msg + (Lib_File, + "is a read-only library", + Prefix => " ", + Minimum_Verbosity => Opt.High); - if not Empty_Q and then Outstanding_Compiles < Max_Process then - declare - Source_Index : Int; - -- Index of the current unit in the current source file + -- The source file that we are checking cannot be located - begin - Extract_From_Q (Source_File, Source_Unit, Source_Index); - Full_Source_File := Osint.Full_Source_Name (Source_File); - Lib_File := Osint.Lib_File_Name - (Source_File, Source_Index); - Full_Lib_File := Osint.Full_Lib_File_Name (Lib_File); + elsif Full_Source_File = No_File then + Record_Failure (Source_File, Source_Unit, False); - -- If this source has already been compiled, the executable is - -- obsolete. + -- Source and library files can be located but are internal + -- files. - if Is_In_Obsoleted (Source_File) then - Executable_Obsolete := True; + elsif not Check_Readonly_Files + and then Full_Lib_File /= No_File + and then Is_Internal_File_Name (Source_File, False) + then + if Force_Compilations then + Fail + ("not allowed to compile """ & + Get_Name_String (Source_File) & + """; use -a switch, or compile file with " & + """-gnatg"" switch"); end if; - -- If the library file is an Ada library skip it - - if Full_Lib_File /= No_File - and then In_Ada_Lib_Dir (Full_Lib_File) - then - Verbose_Msg - (Lib_File, - "is in an Ada library", - Prefix => " ", - Minimum_Verbosity => Opt.High); - - -- If the library file is a read-only library skip it, but - -- only if, when using project files, this library file is - -- in the right object directory (a read-only ALI file - -- in the object directory of a project being extended - -- should not be skipped). - - elsif Full_Lib_File /= No_File - and then not Check_Readonly_Files - and then Is_Readonly_Library (Full_Lib_File) - and then Is_In_Object_Directory (Source_File, Full_Lib_File) - then - Verbose_Msg - (Lib_File, - "is a read-only library", - Prefix => " ", - Minimum_Verbosity => Opt.High); + Verbose_Msg + (Lib_File, + "is an internal library", + Prefix => " ", + Minimum_Verbosity => Opt.High); - -- The source file that we are checking cannot be located + -- The source file that we are checking can be located - elsif Full_Source_File = No_File then - Record_Failure (Source_File, Source_Unit, False); + else + Collect_Arguments (Source_File, Source_Index, + Source_File = Main_Source, Args); - -- Source and library files can be located but are internal - -- files + -- Do nothing if project of source is externally built - elsif not Check_Readonly_Files - and then Full_Lib_File /= No_File - and then Is_Internal_File_Name (Source_File, False) + if Arguments_Project = No_Project + or else not Arguments_Project.Externally_Built then - if Force_Compilations then - Fail - ("not allowed to compile """ & - Get_Name_String (Source_File) & - """; use -a switch, or compile file with " & - """-gnatg"" switch"); + -- Don't waste any time if we have to recompile anyway + + Obj_Stamp := Empty_Time_Stamp; + Need_To_Compile := Force_Compilations; + + if not Force_Compilations then + Check (Source_File => Source_File, + Source_Index => Source_Index, + Is_Main_Source => Source_File = Main_Source, + The_Args => Args, + Lib_File => Lib_File, + Full_Lib_File => Full_Lib_File, + Lib_File_Attr => Lib_File_Attr'Access, + Read_Only => Read_Only, + ALI => ALI, + O_File => Obj_File, + O_Stamp => Obj_Stamp); + Need_To_Compile := (ALI = No_ALI_Id); end if; - Verbose_Msg - (Lib_File, - "is an internal library", - Prefix => " ", - Minimum_Verbosity => Opt.High); + if not Need_To_Compile then + -- The ALI file is up-to-date. Record its Id - -- The source file that we are checking can be located - - else - Collect_Arguments (Source_File, Source_Index, - Source_File = Main_Source, Args); + Record_Good_ALI (ALI); - -- Do nothing if project of source is externally built + -- Record the time stamp of the most recent object + -- file as long as no (re)compilations are needed. - if Arguments_Project = No_Project - or else not Arguments_Project.Externally_Built - then - -- Don't waste any time if we have to recompile anyway - - Obj_Stamp := Empty_Time_Stamp; - Need_To_Compile := Force_Compilations; - - if not Force_Compilations then - Read_Only := - Full_Lib_File /= No_File - and then not Check_Readonly_Files - and then Is_Readonly_Library (Full_Lib_File); - Check (Source_File, Source_Index, - Source_File = Main_Source, Args, Lib_File, - Read_Only, ALI, Obj_File, Obj_Stamp); - Need_To_Compile := (ALI = No_ALI_Id); + if First_Compiled_File = No_File + and then (Most_Recent_Obj_File = No_File + or else Obj_Stamp > Most_Recent_Obj_Stamp) + then + Most_Recent_Obj_File := Obj_File; + Most_Recent_Obj_Stamp := Obj_Stamp; end if; - if not Need_To_Compile then - -- The ALI file is up-to-date. Record its Id - - Record_Good_ALI (ALI); - - -- Record the time stamp of the most recent object - -- file as long as no (re)compilations are needed. - - if First_Compiled_File = No_File - and then (Most_Recent_Obj_File = No_File - or else Obj_Stamp > Most_Recent_Obj_Stamp) - then - Most_Recent_Obj_File := Obj_File; - Most_Recent_Obj_Stamp := Obj_Stamp; - end if; + else + -- Check that switch -x has been used if a source + -- outside of project files need to be compiled. - else - -- Check that switch -x has been used if a source - -- outside of project files need to be compiled. + if Main_Project /= No_Project + and then Arguments_Project = No_Project + and then not External_Unit_Compilation_Allowed + then + Make_Failed ("external source (" + & Get_Name_String (Source_File) + & ") is not part of any project;" + & " cannot be compiled without" + & " gnatmake switch -x"); + end if; - if Main_Project /= No_Project - and then Arguments_Project = No_Project - and then not External_Unit_Compilation_Allowed - then - Make_Failed ("external source (" - & Get_Name_String (Source_File) - & ") is not part of any project;" - & " cannot be compiled without" - & " gnatmake switch -x"); - end if; + -- Is this the first file we have to compile? - -- Is this the first file we have to compile? + if First_Compiled_File = No_File then + First_Compiled_File := Full_Source_File; + Most_Recent_Obj_File := No_File; - if First_Compiled_File = No_File then - First_Compiled_File := Full_Source_File; - Most_Recent_Obj_File := No_File; + if Do_Not_Execute then + -- Exit the main loop - if Do_Not_Execute then - exit Make_Loop; - end if; + return True; end if; + end if; - if In_Place_Mode then + -- Compute where the ALI file must be generated in + -- In_Place_Mode (this does not require to know the + -- location of the object directory) + if In_Place_Mode then + if Full_Lib_File = No_File then -- If the library file was not found, then save -- the library file near the source file. - if Full_Lib_File = No_File then - Lib_File := Osint.Lib_File_Name - (Full_Source_File, Source_Index); + Lib_File := Osint.Lib_File_Name + (Full_Source_File, Source_Index); + Full_Lib_File := Lib_File; - -- If the library file was found, then save the - -- library file in the same place. + else + -- If the library file was found, then save the + -- library file in the same place. + + Lib_File := Full_Lib_File; + end if; + end if; + -- Start the compilation and record it. We can do + -- this because there is at least one free process. + -- This might change the current directory + + Collect_Arguments_And_Compile + (Full_Source_File => Full_Source_File, + Lib_File => Lib_File, + Source_Index => Source_Index, + Pid => Pid, + Process_Created => Process_Created); + + -- Compute where the ALI file will be generated (for + -- cases that might require to know the current + -- directory). The current directory might be changed + -- when compiling other files so we cannot rely on it + -- being the same to find the resulting ALI file. + + if not In_Place_Mode then + -- Compute the expected location of the ALI file. This + -- can be from several places: + -- -i => in place mode. In such a case, + -- Full_Lib_File has already been set above + -- -D => if specified + -- or defaults in current dir + -- We could simply use a call similar to + -- Osint.Full_Lib_File_Name (Lib_File) + -- but that involves system calls and is thus slower + + if Object_Directory_Path /= null then + Name_Len := 0; + Add_Str_To_Name_Buffer (Object_Directory_Path.all); + Add_Str_To_Name_Buffer (Get_Name_String (Lib_File)); + Full_Lib_File := Name_Find; + else + if Project_Of_Current_Object_Directory /= + No_Project + then + Get_Name_String + (Project_Of_Current_Object_Directory + .Object_Directory.Name); + Add_Str_To_Name_Buffer + (Get_Name_String (Lib_File)); + Full_Lib_File := Name_Find; else - Lib_File := Full_Lib_File; + Full_Lib_File := Lib_File; end if; - end if; - -- Start the compilation and record it. We can do - -- this because there is at least one free process. + end if; - Collect_Arguments_And_Compile (Source_Index); + Lib_File_Attr := Unknown_Attributes; - -- Make sure we could successfully start - -- the Compilation. + -- Make sure we could successfully start + -- the Compilation. - if Process_Created then - if Pid = Invalid_Pid then - Record_Failure (Full_Source_File, Source_Unit); - else - Add_Process - (Pid, - Full_Source_File, - Lib_File, - Source_Unit, - Mfile); - end if; + if Process_Created then + if Pid = Invalid_Pid then + Record_Failure (Full_Source_File, Source_Unit); + else + Add_Process + (Pid => Pid, + Sfile => Full_Source_File, + Afile => Lib_File, + Uname => Source_Unit, + Mfile => Mfile, + Full_Lib_File => Full_Lib_File, + Lib_File_Attr => Lib_File_Attr); end if; end if; end if; end if; - end; + end if; end if; + return False; + end Start_Compile_If_Possible; + + ----------------------------- + -- Wait_For_Available_Slot -- + ----------------------------- - -- PHASE 2: Now check if we should wait for a compilation to - -- finish. This is the case if all the available processes are - -- busy compiling sources or there is nothing else to do - -- (that is the Q is empty and there are no good ALIs to process). + procedure Wait_For_Available_Slot is + Compilation_OK : Boolean; + Text : Text_Buffer_Ptr; + ALI : ALI_Id; + Data : Compilation_Data; + begin if Outstanding_Compiles = Max_Process or else (Empty_Q - and then not Good_ALI_Present - and then Outstanding_Compiles > 0) + and then not Good_ALI_Present + and then Outstanding_Compiles > 0) then - Await_Compile - (Full_Source_File, Lib_File, Source_Unit, Compilation_OK); + Await_Compile (Data, Compilation_OK); if not Compilation_OK then - Record_Failure (Full_Source_File, Source_Unit); + Record_Failure (Data.Full_Source_File, Data.Source_Unit); end if; if Compilation_OK or else Keep_Going then @@ -3354,15 +3530,17 @@ package body Make is Check_Object_Consistency; begin - -- If compilation was not OK, or if output is not an - -- object file and we don't do the bind step, don't check - -- for object consistency. + -- If compilation was not OK, or if output is not an object + -- file and we don't do the bind step, don't check for + -- object consistency. Check_Object_Consistency := Check_Object_Consistency and Compilation_OK and (Output_Is_Object or Do_Bind_Step); - Text := Read_Library_Info (Lib_File); + + Text := Read_Library_Info_From_Full + (Data.Full_Lib_File, Data.Lib_File_Attr'Access); -- Restore Check_Object_Consistency to its initial value @@ -3376,8 +3554,8 @@ package body Make is -- the unit just compiled. if Text /= null then - ALI := - Scan_ALI (Lib_File, Text, Ignore_ED => False, Err => True); + ALI := Scan_ALI + (Data.Lib_File, Text, Ignore_ED => False, Err => True); if ALI = No_ALI_Id then @@ -3385,15 +3563,18 @@ package body Make is if Compilation_OK then Inform - (Lib_File, + (Data.Lib_File, "incompatible ALI file, please recompile"); - Record_Failure (Full_Source_File, Source_Unit); + Record_Failure + (Data.Full_Source_File, Data.Source_Unit); end if; + else - Free (Text); Record_Good_ALI (ALI); end if; + Free (Text); + -- If we could not read the ALI file that was just generated -- then there could be a problem reading either the ALI or the -- corresponding object file (if Check_Object_Consistency is @@ -3404,137 +3585,72 @@ package body Make is else if Compilation_OK and not Syntax_Only then Inform - (Lib_File, + (Data.Lib_File, "WARNING: ALI or object file not found after compile"); - Record_Failure (Full_Source_File, Source_Unit); + Record_Failure (Data.Full_Source_File, Data.Source_Unit); end if; end if; end if; end if; + end Wait_For_Available_Slot; - -- PHASE 3: Check if we recorded good ALI files. If yes process - -- them now in the order in which they have been recorded. There - -- are two occasions in which we record good ali files. The first is - -- in phase 1 when, after scanning an existing ALI file we realize - -- it is up-to-date, the second instance is after a successful - -- compilation. - - while Good_ALI_Present loop - ALI := Get_Next_Good_ALI; - - declare - Source_Index : Int := Unit_Index_Of (ALIs.Table (ALI).Afile); - - begin - -- If we are processing the library file corresponding to the - -- main source file check if this source can be a main unit. + -- Start of processing for Compile_Sources - if ALIs.Table (ALI).Sfile = Main_Source and then - Source_Index = Main_Index - then - Main_Unit := ALIs.Table (ALI).Main_Program /= None; - end if; + begin + pragma Assert (Args'First = 1); - -- The following adds the standard library (s-stalib) to the - -- list of files to be handled by gnatmake: this file and any - -- files it depends on are always included in every bind, - -- even if they are not in the explicit dependency list. - -- Of course, it is not added if Suppress_Standard_Library - -- is True. + Outstanding_Compiles := 0; + Running_Compile := new Comp_Data_Arr (1 .. Max_Process); - -- However, to avoid annoying output about s-stalib.ali being - -- read only, when "-v" is used, we add the standard library - -- only when "-a" is used. + -- Package and Queue initializations - if Need_To_Check_Standard_Library then - Check_Standard_Library; - end if; + Good_ALI.Init; - -- Now insert in the Q the unmarked source files (i.e. those - -- which have never been inserted in the Q and hence never - -- considered). Only do that if Unique_Compile is False. + if First_Q_Initialization then + Init_Q; + end if; - if not Unique_Compile then - for J in - ALIs.Table (ALI).First_Unit .. ALIs.Table (ALI).Last_Unit - loop - for K in - Units.Table (J).First_With .. Units.Table (J).Last_With - loop - Sfile := Withs.Table (K).Sfile; - Uname := Withs.Table (K).Uname; + if Initialize_ALI_Data then + Initialize_ALI; + Initialize_ALI_Source; + end if; - -- If project files are used, find the proper source - -- to compile, in case Sfile is the spec, but there - -- is a body. + -- The following two flags affect the behavior of ALI.Set_Source_Table. + -- We set Check_Source_Files to True to ensure that source file + -- time stamps are checked, and we set All_Sources to False to + -- avoid checking the presence of the source files listed in the + -- source dependency section of an ali file (which would be a mistake + -- since the ali file may be obsolete). - if Main_Project /= No_Project then - declare - Unit_Name : Name_Id; - Uid : Prj.Unit_Index; + Check_Source_Files := True; + All_Sources := False; - begin - Get_Name_String (Uname); - Name_Len := Name_Len - 2; - Unit_Name := Name_Find; - Uid := - Units_Htable.Get - (Project_Tree.Units_HT, Unit_Name); - - if Uid /= Prj.No_Unit_Index then - if Uid.File_Names (Impl) /= null - and then - not Uid.File_Names (Impl).Locally_Removed - then - Sfile := Uid.File_Names (Impl).File; - Source_Index := - Uid.File_Names (Impl).Index; - - elsif Uid.File_Names (Spec) /= null - and then - not Uid.File_Names (Spec).Locally_Removed - then - Sfile := Uid.File_Names (Spec).File; - Source_Index := - Uid.File_Names (Spec).Index; - end if; - end if; - end; - end if; + -- Only insert in the Q if it is not already done, to avoid simultaneous + -- compilations if -jnnn is used. - Dependencies.Append ((ALIs.Table (ALI).Sfile, Sfile)); + if not Is_Marked (Main_Source, Main_Index) then + Insert_Q (Main_Source, Index => Main_Index); + Mark (Main_Source, Main_Index); + end if; - if Is_In_Obsoleted (Sfile) then - Executable_Obsolete := True; - end if; + First_Compiled_File := No_File; + Most_Recent_Obj_File := No_File; + Most_Recent_Obj_Stamp := Empty_Time_Stamp; + Main_Unit := False; - if Sfile = No_File then - Debug_Msg - ("Skipping generic:", Withs.Table (K).Uname); + -- Keep looping until there is no more work to do (the Q is empty) + -- and all the outstanding compilations have terminated. - else - Source_Index := - Unit_Index_Of (Withs.Table (K).Afile); + Make_Loop : while not Empty_Q or else Outstanding_Compiles > 0 loop + exit Make_Loop when Must_Exit_Because_Of_Error; + exit Make_Loop when Start_Compile_If_Possible (Args); - if Is_Marked (Sfile, Source_Index) then - Debug_Msg ("Skipping marked file:", Sfile); + Wait_For_Available_Slot; - elsif not Check_Readonly_Files - and then Is_Internal_File_Name (Sfile, False) - then - Debug_Msg ("Skipping internal file:", Sfile); + -- ??? Should be done as soon as we add a Good_ALI, wouldn't it avoid + -- the need for a list of good ALI? - else - Insert_Q - (Sfile, Withs.Table (K).Uname, Source_Index); - Mark (Sfile, Source_Index); - end if; - end if; - end loop; - end loop; - end if; - end; - end loop; + Fill_Queue_From_ALI_Files; if Display_Compilation_Progress then Write_Str ("completed "); @@ -3791,7 +3907,7 @@ package body Make is -- recreate another config file: we cannot reuse the one that -- we just deleted! - Proj.Project.Config_Checked := False; + Proj.Project.Config_Checked := False; Proj.Project.Config_File_Name := No_Path; Proj.Project.Config_File_Temp := False; end if; @@ -3842,8 +3958,8 @@ package body Make is then Temporary_Config_File := False; - -- Do not display the -F=mapping_file switch for - -- gnatbind, if -dn is not specified. + -- Do not display the -F=mapping_file switch for gnatbind + -- if -dn is not specified. elsif Debug.Debug_Flag_N or else Args (J)'Length < 4 @@ -4003,8 +4119,7 @@ package body Make is Total_Compilation_Failures : Natural := 0; Is_Main_Unit : Boolean; - -- Set to True by Compile_Sources if the Main_Source_File can be a - -- main unit. + -- Set True by Compile_Sources if Main_Source_File can be a main unit Main_ALI_File : File_Name_Type; -- The ali file corresponding to Main_Source_File @@ -4013,8 +4128,8 @@ package body Make is -- The file name of an executable Non_Std_Executable : Boolean := False; - -- Non_Std_Executable is set to True when there is a possibility - -- that the linker will not choose the correct executable file name. + -- Non_Std_Executable is set to True when there is a possibility that + -- the linker will not choose the correct executable file name. Current_Work_Dir : constant String_Access := new String'(Get_Current_Dir); @@ -4065,8 +4180,8 @@ package body Make is loop declare Main : constant String := Mains.Next_Main; - -- The name specified on the command line may include - -- directory information. + -- The name specified on the command line may include directory + -- information. File_Name : constant String := Base_Name (Main); -- The simple file name of the current main @@ -4081,17 +4196,16 @@ package body Make is Proj := Prj.Env.Project_Of (File_Name, Main_Project, Project_Tree); - -- Fail if the current main is not a source of a - -- project. + -- Fail if the current main is not a source of a project if Proj = No_Project then Make_Failed ("""" & Main & """ is not a source of any project"); else - -- If there is directory information, check that - -- the source exists and, if it does, that the path - -- is the actual path of a source of a project. + -- If there is directory information, check that the source + -- exists and, if it does, that the path is the actual path + -- of a source of a project. if Main /= File_Name then Lang := Get_Language_From_Name (Main_Project, "ada"); @@ -4165,8 +4279,8 @@ package body Make is elsif Proj /= Real_Main_Project then - -- Fail, as the current main is not a source - -- of the same project as the first main. + -- Fail, as the current main is not a source of the + -- same project as the first main. Make_Failed ("""" & Main & @@ -4176,9 +4290,9 @@ package body Make is end if; end if; - -- If -u and -U are not used, we may have mains that - -- are sources of a project that is not the one - -- specified with switch -P. + -- If -u and -U are not used, we may have mains that are + -- sources of a project that is not the one specified with + -- switch -P. if not Unique_Compile then Main_Project := Real_Main_Project; @@ -4240,8 +4354,7 @@ package body Make is (Unit.File_Names (Impl).Display_File); ALI_Project := Unit.File_Names (Impl).Project; - -- Otherwise, if there is a spec, put it in the - -- mapping. + -- Otherwise, if there is a spec, put it in the mapping elsif Unit.File_Names (Spec) /= No_Source and then Unit.File_Names (Spec).Project /= @@ -4262,8 +4375,9 @@ package body Make is -- If we have something to put in the mapping then do it -- now. However, if the project is extended, we don't put -- anything in the mapping file, because we don't know where - -- the ALI file is: it might be in the extended project obj - -- dir as well as in the extending project obj dir. + -- the ALI file is: it might be in the extended project + -- object directory as well as in the extending project + -- object directory. if ALI_Name /= No_File and then ALI_Project.Extended_By = No_Project @@ -4356,8 +4470,8 @@ package body Make is OK := OK and Status; - -- If the creation of the mapping file was successful, - -- we add the switch to the arguments of gnatbind. + -- If the creation of the mapping file was successful, we add the + -- switch to the arguments of gnatbind. if OK then Last_Arg := Last_Arg + 1; @@ -4369,7 +4483,7 @@ package body Make is -- Start of processing for Gnatmake - -- This body is very long, should be broken down ??? + -- This body is very long, should be broken down??? begin Install_Int_Handler (Sigint_Intercepted'Access); @@ -4422,10 +4536,10 @@ package body Make is end if; -- Specify -n for gnatbind and add the ALI files of all the - -- sources, except the one which is a fake main subprogram: - -- this is the one for the binder generated file and it will be - -- transmitted to gnatlink. These sources are those that are - -- in the queue. + -- sources, except the one which is a fake main subprogram: this + -- is the one for the binder generated file and it will be + -- transmitted to gnatlink. These sources are those that are in + -- the queue. Add_Switch ("-n", Binder, And_Save => True); @@ -4442,8 +4556,8 @@ package body Make is elsif Main_Project /= No_Project then - -- If the main project file is a library project file, main(s) - -- cannot be specified on the command line. + -- If the main project file is a library project file, main(s) cannot + -- be specified on the command line. if Osint.Number_Of_Files /= 0 then if Main_Project.Library @@ -4461,10 +4575,10 @@ package body Make is Check_Mains; end if; - -- If no mains have been specified on the command line, - -- and we are using a project file, we either find the main(s) - -- in the attribute Main of the main project, or we put all - -- the sources of the project file as mains. + -- If no mains have been specified on the command line, and we are + -- using a project file, we either find the main(s) in attribute + -- Main of the main project, or we put all the sources of the project + -- file as mains. else if Main_Index /= 0 then @@ -4476,16 +4590,16 @@ package body Make is Value : String_List_Id := Main_Project.Mains; begin - -- The attribute Main is an empty list or not specified, - -- or else gnatmake was invoked with the switch "-u". + -- The attribute Main is an empty list or not specified, or + -- else gnatmake was invoked with the switch "-u". if Value = Prj.Nil_String or else Unique_Compile then if (not Make_Steps) or else Compile_Only or else not Main_Project.Library then - -- First make sure that the binder and the linker - -- will not be invoked. + -- First make sure that the binder and the linker will + -- not be invoked. Do_Bind_Step := False; Do_Link_Step := False; @@ -4513,8 +4627,8 @@ package body Make is else -- The attribute Main is not an empty list. - -- Put all the main subprograms in the list as if there - -- were specified on the command line. However, if attribute + -- Put all the main subprograms in the list as if they were + -- specified on the command line. However, if attribute -- Languages includes a language other than Ada, only -- include the Ada mains; if there is no Ada main, compile -- all the sources of the project. @@ -4778,8 +4892,8 @@ package body Make is & """ is not a unit of project " & Project_File_Name.all & "."); else - -- Remove any directory information from the main - -- source file name. + -- Remove any directory information from the main source file + -- file name. declare Pos : Natural := Main_Unit_File_Name'Last; @@ -5051,8 +5165,8 @@ package body Make is end if; -- Get the target parameters, which are only needed for a couple of - -- cases in gnatmake. Protect against an exception, such as the case - -- of system.ads missing from the library, and fail gracefully. + -- cases in gnatmake. Protect against an exception, such as the case of + -- system.ads missing from the library, and fail gracefully. begin Targparm.Get_Target_Parameters; @@ -5145,8 +5259,8 @@ package body Make is end; end if; - -- If a relative path output file has been specified, we add - -- the exec directory. + -- If a relative path output file has been specified, we add the + -- exec directory. for J in reverse 1 .. Saved_Linker_Switches.Last - 1 loop if Saved_Linker_Switches.Table (J).all = Output_Flag.all then @@ -5267,9 +5381,9 @@ package body Make is The_Saved_Gcc_Switches (The_Saved_Gcc_Switches'Last) := No_gnat_adc; end if; - -- If there was a --GCC, --GNATBIND or --GNATLINK switch on - -- the command line, then we have to use it, even if there was - -- another switch in the project file. + -- If there was a --GCC, --GNATBIND or --GNATLINK switch on the command + -- line, then we have to use it, even if there was another switch in + -- the project file. if Saved_Gcc /= null then Gcc := Saved_Gcc; @@ -6586,8 +6700,8 @@ package body Make is Mains.Delete; - -- Add the directory where gnatmake is invoked in front of the - -- path, if gnatmake is invoked from a bin directory or with directory + -- Add the directory where gnatmake is invoked in front of the path, + -- if gnatmake is invoked from a bin directory or with directory -- information. Only do this if the platform is not VMS, where the -- notion of path does not really exist. @@ -6755,8 +6869,8 @@ package body Make is Write_Eol; end if; - -- We add the source directories and the object directories - -- to the search paths. + -- We add the source directories and the object directories to the + -- search paths. Add_Source_Directories (Main_Project, Project_Tree); Add_Object_Directories (Main_Project); @@ -6917,9 +7031,8 @@ package body Make is and then not Unit.File_Names (Spec).Locally_Removed and then Check_Project (Unit.File_Names (Spec).Project) then - -- If there is no source for the body, but there is a source - -- for the spec which has not been locally removed, then we take - -- this one. + -- If there is no source for the body, but there is one for the + -- spec which has not been locally removed, then we take this one. Sfile := Unit.File_Names (Spec).Display_File; Index := Unit.File_Names (Spec).Index; @@ -7263,9 +7376,9 @@ package body Make is B : Byte; function Base_Directory return String; - -- If Dir comes from the command line, empty string (relative paths - -- are resolved with respect to the current directory), else return - -- the main project's directory. + -- If Dir comes from the command line, empty string (relative paths are + -- resolved with respect to the current directory), else return the main + -- project's directory. -------------------- -- Base_Directory -- @@ -7372,7 +7485,7 @@ package body Make is Multilib_Gcc_Path := GNAT.OS_Lib.Locate_Exec_On_Path (Multilib_Gcc.all); - Create_Temp_File (Output_FD, Output_Name); + Create_Temp_Output_File (Output_FD, Output_Name); if Output_FD = Invalid_FD then return; @@ -7566,7 +7679,7 @@ package body Make is -- If the previous switch has set the Object_Directory_Present flag -- (that is we have seen a -D), then the next argument is the path name - -- of the object directory.. + -- of the object directory. elsif Object_Directory_Present and then not Object_Directory_Seen @@ -7580,21 +7693,26 @@ package body Make is Make_Failed ("cannot find object directory """ & Argv & """"); else - Add_Lib_Search_Dir (Argv); + -- Record the object directory. Make sure it ends with a directory + -- separator. - -- Specify the object directory to the binder + declare + Norm : constant String := Normalize_Pathname (Argv); + begin + if Norm (Norm'Last) = Directory_Separator then + Object_Directory_Path := new String'(Norm); + else + Object_Directory_Path := + new String'(Norm & Directory_Separator); + end if; - Add_Switch ("-aO" & Argv, Binder, And_Save => And_Save); + Add_Lib_Search_Dir (Norm); - -- Record the object directory. Make sure it ends with a directory - -- separator. + -- Specify the object directory to the binder + + Add_Switch ("-aO" & Norm, Binder, And_Save => And_Save); + end; - if Argv (Argv'Last) = Directory_Separator then - Object_Directory_Path := new String'(Argv); - else - Object_Directory_Path := - new String'(Argv & Directory_Separator); - end if; end if; -- Then check if we are dealing with -cargs/-bargs/-largs/-margs @@ -7617,9 +7735,8 @@ package body Make is raise Program_Error; end case; - -- A special test is needed for the -o switch within a -largs - -- since that is another way to specify the name of the final - -- executable. + -- A special test is needed for the -o switch within a -largs since that + -- is another way to specify the name of the final executable. elsif Program_Args = Linker and then Argv = "-o" @@ -7627,8 +7744,8 @@ package body Make is Make_Failed ("switch -o not allowed within a -largs. " & "Use -o directly."); - -- Check to see if we are reading switches after a -cargs, - -- -bargs or -largs switch. If yes save it. + -- Check to see if we are reading switches after a -cargs, -bargs or + -- -largs switch. If so, save it. elsif Program_Args /= None then @@ -7671,9 +7788,7 @@ package body Make is for J in 2 .. Program_Args.all'Last loop Add_Switch - (Program_Args.all (J).all, - Compiler, - And_Save => And_Save); + (Program_Args.all (J).all, Compiler, And_Save => And_Save); end loop; end; @@ -7721,7 +7836,7 @@ package body Make is Argv (1 .. 5) = "--RTS" then Add_Switch (Argv, Compiler, And_Save => And_Save); - Add_Switch (Argv, Binder, And_Save => And_Save); + Add_Switch (Argv, Binder, And_Save => And_Save); if Argv'Length <= 6 or else Argv (6) /= '=' then Make_Failed ("missing path for --RTS"); @@ -7784,7 +7899,7 @@ package body Make is Argv (1 .. 8) = "--param=" then Add_Switch (Argv, Compiler, And_Save => And_Save); - Add_Switch (Argv, Linker, And_Save => And_Save); + Add_Switch (Argv, Linker, And_Save => And_Save); else Scan_Make_Switches (Project_Node_Tree, Argv, Success); @@ -7822,18 +7937,17 @@ package body Make is -- -Idir elsif Argv (2) = 'I' then - Add_Source_Search_Dir (Argv (3 .. Argv'Last), And_Save); + Add_Source_Search_Dir (Argv (3 .. Argv'Last), And_Save); Add_Library_Search_Dir (Argv (3 .. Argv'Last), And_Save); Add_Switch (Argv, Compiler, And_Save => And_Save); - Add_Switch (Argv, Binder, And_Save => And_Save); + Add_Switch (Argv, Binder, And_Save => And_Save); -- -aIdir (to gcc this is like a -I switch) elsif Argv'Length >= 3 and then Argv (2 .. 3) = "aI" then Add_Source_Search_Dir (Argv (4 .. Argv'Last), And_Save); - Add_Switch ("-I" & Argv (4 .. Argv'Last), - Compiler, - And_Save => And_Save); + Add_Switch + ("-I" & Argv (4 .. Argv'Last), Compiler, And_Save => And_Save); Add_Switch (Argv, Binder, And_Save => And_Save); -- -aOdir @@ -7847,9 +7961,8 @@ package body Make is elsif Argv'Length >= 3 and then Argv (2 .. 3) = "aL" then Mark_Directory (Argv (4 .. Argv'Last), Ada_Lib_Dir, And_Save); Add_Library_Search_Dir (Argv (4 .. Argv'Last), And_Save); - Add_Switch ("-aO" & Argv (4 .. Argv'Last), - Binder, - And_Save => And_Save); + Add_Switch + ("-aO" & Argv (4 .. Argv'Last), Binder, And_Save => And_Save); -- -aamp_target=... @@ -7867,14 +7980,12 @@ package body Make is elsif Argv (2) = 'A' then Mark_Directory (Argv (3 .. Argv'Last), Ada_Lib_Dir, And_Save); - Add_Source_Search_Dir (Argv (3 .. Argv'Last), And_Save); + Add_Source_Search_Dir (Argv (3 .. Argv'Last), And_Save); Add_Library_Search_Dir (Argv (3 .. Argv'Last), And_Save); - Add_Switch ("-I" & Argv (3 .. Argv'Last), - Compiler, - And_Save => And_Save); - Add_Switch ("-aO" & Argv (3 .. Argv'Last), - Binder, - And_Save => And_Save); + Add_Switch + ("-I" & Argv (3 .. Argv'Last), Compiler, And_Save => And_Save); + Add_Switch + ("-aO" & Argv (3 .. Argv'Last), Binder, And_Save => And_Save); -- -Ldir @@ -7882,11 +7993,11 @@ package body Make is Add_Switch (Argv, Linker, And_Save => And_Save); -- For -gxxxxx, -pg, -mxxx, -fxxx: give the switch to both the - -- compiler and the linker (except for -gnatxxx which is only for - -- the compiler). Some of the -mxxx (for example -m64) and -fxxx - -- (for example -ftest-coverage for gcov) need to be used when - -- compiling the binder generated files, and using all these gcc - -- switches for the binder generated files should not be a problem. + -- compiler and the linker (except for -gnatxxx which is only for the + -- compiler). Some of the -mxxx (for example -m64) and -fxxx (for + -- example -ftest-coverage for gcov) need to be used when compiling + -- the binder generated files, and using all these gcc switches for + -- the binder generated files should not be a problem. elsif (Argv (2) = 'g' and then (Argv'Last < 5 @@ -7896,7 +8007,7 @@ package body Make is or else (Argv (2) = 'f' and then Argv'Last > 2) then Add_Switch (Argv, Compiler, And_Save => And_Save); - Add_Switch (Argv, Linker, And_Save => And_Save); + Add_Switch (Argv, Linker, And_Save => And_Save); -- The following condition has to be kept synchronized with -- the Process_Multilib one. @@ -7922,8 +8033,8 @@ package body Make is elsif Argv'Last = 2 and then Argv (2) = 'D' then if Project_File_Name /= null then - Make_Failed ("-D cannot be used in conjunction with a " & - "project file"); + Make_Failed + ("-D cannot be used in conjunction with a project file"); else Scan_Make_Switches (Project_Node_Tree, Argv, Success); @@ -7931,17 +8042,15 @@ package body Make is -- -d - elsif Argv (2) = 'd' - and then Argv'Last = 2 - then + elsif Argv (2) = 'd' and then Argv'Last = 2 then Display_Compilation_Progress := True; -- -i elsif Argv'Last = 2 and then Argv (2) = 'i' then if Project_File_Name /= null then - Make_Failed ("-i cannot be used in conjunction with a " & - "project file"); + Make_Failed + ("-i cannot be used in conjunction with a project file"); else Scan_Make_Switches (Project_Node_Tree, Argv, Success); end if; @@ -7957,20 +8066,16 @@ package body Make is -- -m - elsif Argv (2) = 'm' - and then Argv'Last = 2 - then + elsif Argv (2) = 'm' and then Argv'Last = 2 then Minimal_Recompilation := True; -- -u - elsif Argv (2) = 'u' - and then Argv'Last = 2 - then - Unique_Compile := True; - Compile_Only := True; - Do_Bind_Step := False; - Do_Link_Step := False; + elsif Argv (2) = 'u' and then Argv'Last = 2 then + Unique_Compile := True; + Compile_Only := True; + Do_Bind_Step := False; + Do_Link_Step := False; -- -U @@ -7978,10 +8083,10 @@ package body Make is and then Argv'Last = 2 then Unique_Compile_All_Projects := True; - Unique_Compile := True; - Compile_Only := True; - Do_Bind_Step := False; - Do_Link_Step := False; + Unique_Compile := True; + Compile_Only := True; + Do_Bind_Step := False; + Do_Link_Step := False; -- -Pprj or -P prj (only once, and only on the command line) @@ -7990,16 +8095,16 @@ package body Make is Make_Failed ("cannot have several project files specified"); elsif Object_Directory_Path /= null then - Make_Failed ("-D cannot be used in conjunction with a " & - "project file"); + Make_Failed + ("-D cannot be used in conjunction with a project file"); elsif In_Place_Mode then - Make_Failed ("-i cannot be used in conjunction with a " & - "project file"); + Make_Failed + ("-i cannot be used in conjunction with a project file"); elsif not And_Save then - -- It could be a tool other than gnatmake (i.e, gnatdist) + -- It could be a tool other than gnatmake (e.g. gnatdist) -- or a -P switch inside a project file. Fail @@ -8040,31 +8145,30 @@ package body Make is elsif Argv (2) = 'X' and then Is_External_Assignment (Project_Node_Tree, Argv) then - -- Is_External_Assignment has side effects - -- when it returns True; + -- Is_External_Assignment has side effects when it returns True null; - -- If -gnath is present, then generate the usage information - -- right now and do not pass this option on to the compiler calls. + -- If -gnath is present, then generate the usage information right + -- now and do not pass this option on to the compiler calls. elsif Argv = "-gnath" then Usage; - -- If -gnatc is specified, make sure the bind step and the link - -- step are not executed. + -- If -gnatc is specified, make sure the bind and link steps are not + -- executed. elsif Argv'Length >= 6 and then Argv (2 .. 6) = "gnatc" then - -- If -gnatc is specified, make sure the bind step and the link - -- step are not executed. + -- If -gnatc is specified, make sure the bind and link steps are + -- not executed. Add_Switch (Argv, Compiler, And_Save => And_Save); - Operating_Mode := Check_Semantics; + Operating_Mode := Check_Semantics; Check_Object_Consistency := False; Compile_Only := True; - Do_Bind_Step := False; - Do_Link_Step := False; + Do_Bind_Step := False; + Do_Link_Step := False; elsif Argv (2 .. Argv'Last) = "nostdlib" then @@ -8082,7 +8186,7 @@ package body Make is No_Stdinc := True; Add_Switch (Argv, Compiler, And_Save => And_Save); - Add_Switch (Argv, Binder, And_Save => And_Save); + Add_Switch (Argv, Binder, And_Save => And_Save); -- All other switches are processed by Scan_Make_Switches. If the -- call returns with Gnatmake_Switch_Found = False, then the switch diff --git a/gcc/ada/makeutl.adb b/gcc/ada/makeutl.adb index a570737d711..307ec6ffccc 100644 --- a/gcc/ada/makeutl.adb +++ b/gcc/ada/makeutl.adb @@ -25,6 +25,7 @@ with ALI; use ALI; with Debug; +with Fname; with Osint; use Osint; with Output; use Output; with Opt; use Opt; @@ -213,31 +214,35 @@ package body Makeutl is if Unit_Name /= No_Name then -- For separates, the file is no longer associated with the - -- unit ("proc-sep.adb" is not associated with unit "proc.sep". - -- So we need to check whether the source file still exists in + -- unit ("proc-sep.adb" is not associated with unit "proc.sep") + -- so we need to check whether the source file still exists in -- the source tree: it will if it matches the naming scheme -- (and then will be for the same unit). if Find_Source - (In_Tree => Project_Tree, - Project => No_Project, - Base_Name => SD.Sfile) = No_Source + (In_Tree => Project_Tree, + Project => No_Project, + Base_Name => SD.Sfile) = No_Source then - -- If this is not a runtime file (when using -a) ? Otherwise - -- we get complaints about a-except.adb, which uses - -- separates. - - if not Check_Readonly_Files - or else Find_File (SD.Sfile, Osint.Source) = No_File + -- If this is not a runtime file or if, when gnatmake switch + -- -a is used, we are not able to find this subunit in the + -- source directories, then recompilation is needed. + + if not Fname.Is_Internal_File_Name (SD.Sfile) + or else + (Check_Readonly_Files + and then Find_File (SD.Sfile, Osint.Source) = No_File) then if Verbose_Mode then Write_Line - ("While parsing ALI file: Sdep associates " + ("While parsing ALI file, file " & Get_Name_String (SD.Sfile) - & " with unit " & Get_Name_String (Unit_Name) + & " is indicated as containing subunit " + & Get_Name_String (Unit_Name) & " but this does not match what was found while" & " parsing the project. Will recompile"); end if; + return False; end if; end if; @@ -323,7 +328,9 @@ package body Makeutl is return ""; end if; - return Normalize_Pathname (Exec (Exec'First .. Path_Last - 4)) + return Normalize_Pathname + (Exec (Exec'First .. Path_Last - 4), + Resolve_Links => Opt.Follow_Links_For_Dirs) & Directory_Separator; end Get_Install_Dir; diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads index d184da9aa54..542b1f02551 100644 --- a/gcc/ada/opt.ads +++ b/gcc/ada/opt.ads @@ -663,7 +663,7 @@ package Opt is -- still valid if they point to a file which is outside of the project), -- and that no directory has a name which is a valid source name. - Follow_Links_For_Dirs : Boolean := True; + Follow_Links_For_Dirs : Boolean := False; -- PROJECT MANAGER -- Set to True if directories can be links in this project, and therefore -- additional system calls must be performed to ensure that we always see @@ -1361,6 +1361,11 @@ package Opt is -- Set to True to generate warnings on use of any feature in Annex or if a -- subprogram is called for which a pragma Obsolescent applies. + Warn_On_Overlap : Boolean := False; + -- GNAT + -- Set to True to generate warnings when a writable actual which is not + -- a by-copy type overlaps with another actual in a subprogram call. + Warn_On_Questionable_Missing_Parens : Boolean := True; -- GNAT -- Set to True to generate warnings for cases where parentheses are missing diff --git a/gcc/ada/osint.adb b/gcc/ada/osint.adb index a02e1eefe7e..1b1f5085984 100644 --- a/gcc/ada/osint.adb +++ b/gcc/ada/osint.adb @@ -80,7 +80,8 @@ package body Osint is -- Appends Suffix to Name and returns the new name function OS_Time_To_GNAT_Time (T : OS_Time) return Time_Stamp_Type; - -- Convert OS format time to GNAT format time stamp + -- Convert OS format time to GNAT format time stamp. + -- Returns Empty_Time_Stamp if T is Invalid_Time function Executable_Prefix return String_Ptr; -- Returns the name of the root directory where the executable is stored. @@ -93,16 +94,39 @@ package body Osint is -- Update the specified path to replace the prefix with the location -- where GNAT is installed. See the file prefix.c in GCC for details. - function Locate_File - (N : File_Name_Type; - T : File_Type; - Dir : Natural; - Name : String) return File_Name_Type; + procedure Locate_File + (N : File_Name_Type; + T : File_Type; + Dir : Natural; + Name : String; + Found : out File_Name_Type; + Attr : access File_Attributes); -- See if the file N whose name is Name exists in directory Dir. Dir is an -- index into the Lib_Search_Directories table if T = Library. Otherwise -- if T = Source, Dir is an index into the Src_Search_Directories table. -- Returns the File_Name_Type of the full file name if file found, or -- No_File if not found. + -- On exit, Found is set to the file that was found, and Attr to a cache of + -- its attributes (at least those that have been computed so far). Reusing + -- the cache will save some system calls. + -- Attr is always reset in this call to Unknown_Attributes, even in case of + -- failure + + procedure Find_File + (N : File_Name_Type; + T : File_Type; + Found : out File_Name_Type; + Attr : access File_Attributes); + -- A version of Find_File that also returns a cache of the file attributes + -- for later reuse + + procedure Smart_Find_File + (N : File_Name_Type; + T : File_Type; + Found : out File_Name_Type; + Attr : out File_Attributes); + -- A version of Smart_Find_File that also returns a cache of the file + -- attributes for later reuse function C_String_Length (S : Address) return Integer; -- Returns length of a C string (zero for a null address) @@ -211,18 +235,17 @@ package body Osint is function File_Hash (F : File_Name_Type) return File_Hash_Num; -- Compute hash index for use by Simple_HTable - package File_Name_Hash_Table is new GNAT.HTable.Simple_HTable ( - Header_Num => File_Hash_Num, - Element => File_Name_Type, - No_Element => No_File, - Key => File_Name_Type, - Hash => File_Hash, - Equal => "="); + type File_Info_Cache is record + File : File_Name_Type; + Attr : aliased File_Attributes; + end record; + No_File_Info_Cache : constant File_Info_Cache := + (No_File, Unknown_Attributes); - package File_Stamp_Hash_Table is new GNAT.HTable.Simple_HTable ( + package File_Name_Hash_Table is new GNAT.HTable.Simple_HTable ( Header_Num => File_Hash_Num, - Element => Time_Stamp_Type, - No_Element => Empty_Time_Stamp, + Element => File_Info_Cache, + No_Element => No_File_Info_Cache, Key => File_Name_Type, Hash => File_Hash, Equal => "="); @@ -559,9 +582,25 @@ package body Osint is Fail ("missing library directory name"); end if; - Lib_Search_Directories.Increment_Last; - Lib_Search_Directories.Table (Lib_Search_Directories.Last) := - Normalize_Directory_Name (Dir); + declare + Norm : String_Ptr := Normalize_Directory_Name (Dir); + begin + + -- Do nothing if the directory is already in the list. This saves + -- system calls and avoid unneeded work + + for D in Lib_Search_Directories.First .. + Lib_Search_Directories.Last + loop + if Lib_Search_Directories.Table (D).all = Norm.all then + Free (Norm); + return; + end if; + end loop; + + Lib_Search_Directories.Increment_Last; + Lib_Search_Directories.Table (Lib_Search_Directories.Last) := Norm; + end; end Add_Lib_Search_Dir; --------------------- @@ -958,6 +997,33 @@ package body Osint is return File_Hash_Num (Int (F) rem File_Hash_Num'Range_Length); end File_Hash; + ----------------- + -- File_Length -- + ----------------- + + function File_Length + (Name : C_File_Name; Attr : access File_Attributes) return Long_Integer + is + function Internal + (F : Integer; N : C_File_Name; A : System.Address) return Long_Integer; + pragma Import (C, Internal, "__gnat_file_length_attr"); + begin + return Internal (-1, Name, Attr.all'Address); + end File_Length; + + --------------------- + -- File_Time_Stamp -- + --------------------- + + function File_Time_Stamp + (Name : C_File_Name; Attr : access File_Attributes) return OS_Time + is + function Internal (N : C_File_Name; A : System.Address) return OS_Time; + pragma Import (C, Internal, "__gnat_file_time_name_attr"); + begin + return Internal (Name, Attr.all'Address); + end File_Time_Stamp; + ---------------- -- File_Stamp -- ---------------- @@ -970,12 +1036,13 @@ package body Osint is Get_Name_String (Name); - if not Is_Regular_File (Name_Buffer (1 .. Name_Len)) then - return Empty_Time_Stamp; - else - Name_Buffer (Name_Len + 1) := ASCII.NUL; - return OS_Time_To_GNAT_Time (File_Time_Stamp (Name_Buffer)); - end if; + -- File_Time_Stamp will always return Invalid_Time if the file does not + -- exist, and OS_Time_To_GNAT_Time will convert this value to + -- Empty_Time_Stamp. Therefore we do not need to first test whether the + -- file actually exists, which saves a system call. + + return OS_Time_To_GNAT_Time + (File_Time_Stamp (Name_Buffer (1 .. Name_Len))); end File_Stamp; function File_Stamp (Name : Path_Name_Type) return Time_Stamp_Type is @@ -991,6 +1058,22 @@ package body Osint is (N : File_Name_Type; T : File_Type) return File_Name_Type is + Attr : aliased File_Attributes; + Found : File_Name_Type; + begin + Find_File (N, T, Found, Attr'Access); + return Found; + end Find_File; + + --------------- + -- Find_File -- + --------------- + + procedure Find_File + (N : File_Name_Type; + T : File_Type; + Found : out File_Name_Type; + Attr : access File_Attributes) is begin Get_Name_String (N); @@ -1014,7 +1097,9 @@ package body Osint is (Hostparm.OpenVMS and then Name_Buffer (Name_Len - 2 .. Name_Len) = "_dg"))) then - return N; + Found := N; + Attr.all := Unknown_Attributes; + return; -- If we are trying to find the current main file just look in the -- directory where the user said it was. @@ -1022,7 +1107,8 @@ package body Osint is elsif Look_In_Primary_Directory_For_Current_Main and then Current_Main = N then - return Locate_File (N, T, Primary_Directory, File_Name); + Locate_File (N, T, Primary_Directory, File_Name, Found, Attr); + return; -- Otherwise do standard search for source file @@ -1040,21 +1126,23 @@ package body Osint is -- return No_File, indicating the file is not a source. if File = Error_File_Name then - return No_File; - + Found := No_File; else - return File; + Found := File; end if; + + Attr.all := Unknown_Attributes; + return; end if; -- First place to look is in the primary directory (i.e. the same -- directory as the source) unless this has been disabled with -I- if Opt.Look_In_Primary_Dir then - File := Locate_File (N, T, Primary_Directory, File_Name); + Locate_File (N, T, Primary_Directory, File_Name, Found, Attr); - if File /= No_File then - return File; + if Found /= No_File then + return; end if; end if; @@ -1067,14 +1155,15 @@ package body Osint is end if; for D in Primary_Directory + 1 .. Last_Dir loop - File := Locate_File (N, T, D, File_Name); + Locate_File (N, T, D, File_Name, Found, Attr); - if File /= No_File then - return File; + if Found /= No_File then + return; end if; end loop; - return No_File; + Attr.all := Unknown_Attributes; + Found := No_File; end if; end; end Find_File; @@ -1146,9 +1235,28 @@ package body Osint is -- Full_Lib_File_Name -- ------------------------ + procedure Full_Lib_File_Name + (N : File_Name_Type; + Lib_File : out File_Name_Type; + Attr : out File_Attributes) + is + A : aliased File_Attributes; + begin + -- ??? seems we could use Smart_Find_File here + Find_File (N, Library, Lib_File, A'Access); + Attr := A; + end Full_Lib_File_Name; + + ------------------------ + -- Full_Lib_File_Name -- + ------------------------ + function Full_Lib_File_Name (N : File_Name_Type) return File_Name_Type is + Attr : File_Attributes; + File : File_Name_Type; begin - return Find_File (N, Library); + Full_Lib_File_Name (N, File, Attr); + return File; end Full_Lib_File_Name; ---------------------------- @@ -1187,6 +1295,18 @@ package body Osint is return Smart_Find_File (N, Source); end Full_Source_Name; + ---------------------- + -- Full_Source_Name -- + ---------------------- + + procedure Full_Source_Name + (N : File_Name_Type; + Full_File : out File_Name_Type; + Attr : access File_Attributes) is + begin + Smart_Find_File (N, Source, Full_File, Attr.all); + end Full_Source_Name; + ------------------- -- Get_Directory -- ------------------- @@ -1468,6 +1588,19 @@ package body Osint is Lib_Search_Directories.Table (Primary_Directory) := new String'(""); end Initialize; + ------------------ + -- Is_Directory -- + ------------------ + + function Is_Directory + (Name : C_File_Name; Attr : access File_Attributes) return Boolean + is + function Internal (N : C_File_Name; A : System.Address) return Integer; + pragma Import (C, Internal, "__gnat_is_directory_attr"); + begin + return Internal (Name, Attr.all'Address) /= 0; + end Is_Directory; + ---------------------------- -- Is_Directory_Separator -- ---------------------------- @@ -1499,6 +1632,71 @@ package body Osint is return not Is_Writable_File (Name_Buffer (1 .. Name_Len)); end Is_Readonly_Library; + ------------------------ + -- Is_Executable_File -- + ------------------------ + + function Is_Executable_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean + is + function Internal (N : C_File_Name; A : System.Address) return Integer; + pragma Import (C, Internal, "__gnat_is_executable_file_attr"); + begin + return Internal (Name, Attr.all'Address) /= 0; + end Is_Executable_File; + + ---------------------- + -- Is_Readable_File -- + ---------------------- + + function Is_Readable_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean + is + function Internal (N : C_File_Name; A : System.Address) return Integer; + pragma Import (C, Internal, "__gnat_is_readable_file_attr"); + begin + return Internal (Name, Attr.all'Address) /= 0; + end Is_Readable_File; + + --------------------- + -- Is_Regular_File -- + --------------------- + + function Is_Regular_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean + is + function Internal (N : C_File_Name; A : System.Address) return Integer; + pragma Import (C, Internal, "__gnat_is_regular_file_attr"); + begin + return Internal (Name, Attr.all'Address) /= 0; + end Is_Regular_File; + + ---------------------- + -- Is_Symbolic_Link -- + ---------------------- + + function Is_Symbolic_Link + (Name : C_File_Name; Attr : access File_Attributes) return Boolean + is + function Internal (N : C_File_Name; A : System.Address) return Integer; + pragma Import (C, Internal, "__gnat_is_symbolic_link_attr"); + begin + return Internal (Name, Attr.all'Address) /= 0; + end Is_Symbolic_Link; + + ---------------------- + -- Is_Writable_File -- + ---------------------- + + function Is_Writable_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean + is + function Internal (N : C_File_Name; A : System.Address) return Integer; + pragma Import (C, Internal, "__gnat_is_writable_file_attr"); + begin + return Internal (Name, Attr.all'Address) /= 0; + end Is_Writable_File; + ------------------- -- Lib_File_Name -- ------------------- @@ -1527,24 +1725,17 @@ package body Osint is return Name_Find; end Lib_File_Name; - ------------------------ - -- Library_File_Stamp -- - ------------------------ - - function Library_File_Stamp (N : File_Name_Type) return Time_Stamp_Type is - begin - return File_Stamp (Find_File (N, Library)); - end Library_File_Stamp; - ----------------- -- Locate_File -- ----------------- - function Locate_File - (N : File_Name_Type; - T : File_Type; - Dir : Natural; - Name : String) return File_Name_Type + procedure Locate_File + (N : File_Name_Type; + T : File_Type; + Dir : Natural; + Name : String; + Found : out File_Name_Type; + Attr : access File_Attributes) is Dir_Name : String_Ptr; @@ -1557,29 +1748,34 @@ package body Osint is elsif T = Library then Dir_Name := Lib_Search_Directories.Table (Dir); - else pragma Assert (T /= Config); + else + pragma Assert (T /= Config); Dir_Name := Src_Search_Directories.Table (Dir); end if; declare - Full_Name : String (1 .. Dir_Name'Length + Name'Length); + Full_Name : String (1 .. Dir_Name'Length + Name'Length + 1); begin Full_Name (1 .. Dir_Name'Length) := Dir_Name.all; - Full_Name (Dir_Name'Length + 1 .. Full_Name'Length) := Name; + Full_Name (Dir_Name'Length + 1 .. Full_Name'Last - 1) := Name; + Full_Name (Full_Name'Last) := ASCII.NUL; + + Attr.all := Unknown_Attributes; - if not Is_Regular_File (Full_Name) then - return No_File; + if not Is_Regular_File (Full_Name'Address, Attr) then + Found := No_File; else -- If the file is in the current directory then return N itself if Dir_Name'Length = 0 then - return N; + Found := N; else - Name_Len := Full_Name'Length; - Name_Buffer (1 .. Name_Len) := Full_Name; - return Name_Enter; + Name_Len := Full_Name'Length - 1; + Name_Buffer (1 .. Name_Len) := + Full_Name (1 .. Full_Name'Last - 1); + Found := Name_Find; -- ??? Was Name_Enter, no obvious reason end if; end if; end; @@ -1599,11 +1795,13 @@ package body Osint is declare File_Name : constant String := Name_Buffer (1 .. Name_Len); File : File_Name_Type := No_File; + Attr : aliased File_Attributes; Last_Dir : Natural; begin if Opt.Look_In_Primary_Dir then - File := Locate_File (N, Source, Primary_Directory, File_Name); + Locate_File + (N, Source, Primary_Directory, File_Name, File, Attr'Access); if File /= No_File and then T = File_Stamp (N) then return File; @@ -1613,7 +1811,7 @@ package body Osint is Last_Dir := Src_Search_Directories.Last; for D in Primary_Directory + 1 .. Last_Dir loop - File := Locate_File (N, Source, D, File_Name); + Locate_File (N, Source, D, File_Name, File, Attr'Access); if File /= No_File and then T = File_Stamp (File) then return File; @@ -1887,6 +2085,10 @@ package body Osint is S : Second_Type; begin + if T = Invalid_Time then + return Empty_Time_Stamp; + end if; + GM_Split (T, Y, Mo, D, H, Mn, S); Make_Time_Stamp (Year => Nat (Y), @@ -2114,11 +2316,34 @@ package body Osint is function Read_Library_Info (Lib_File : File_Name_Type; Fatal_Err : Boolean := False) return Text_Buffer_Ptr + is + File : File_Name_Type; + Attr : aliased File_Attributes; + begin + Find_File (Lib_File, Library, File, Attr'Access); + return Read_Library_Info_From_Full + (Full_Lib_File => File, + Lib_File_Attr => Attr'Access, + Fatal_Err => Fatal_Err); + end Read_Library_Info; + + --------------------------------- + -- Read_Library_Info_From_Full -- + --------------------------------- + + function Read_Library_Info_From_Full + (Full_Lib_File : File_Name_Type; + Lib_File_Attr : access File_Attributes; + Fatal_Err : Boolean := False) return Text_Buffer_Ptr is Lib_FD : File_Descriptor; -- The file descriptor for the current library file. A negative value -- indicates failure to open the specified source file. + Len : Integer; + -- Length of source file text (ALI). If it doesn't fit in an integer + -- we're probably stuck anyway (>2 gigs of source seems a lot!) + Text : Text_Buffer_Ptr; -- Allocated text buffer @@ -2127,7 +2352,7 @@ package body Osint is -- For the calls to Close begin - Current_Full_Lib_Name := Find_File (Lib_File, Library); + Current_Full_Lib_Name := Full_Lib_File; Current_Full_Obj_Name := Object_File_Name (Current_Full_Lib_Name); if Current_Full_Lib_Name = No_File then @@ -2158,17 +2383,32 @@ package body Osint is end if; end if; + -- Compute the length of the file (potentially also preparing other data + -- like the timestamp and whether the file is read-only, for future use) + + Len := Integer (File_Length (Name_Buffer'Address, Lib_File_Attr)); + -- Check for object file consistency if requested if Opt.Check_Object_Consistency then - Current_Full_Lib_Stamp := File_Stamp (Current_Full_Lib_Name); + -- On most systems, this does not result in an extra system call + Current_Full_Lib_Stamp := OS_Time_To_GNAT_Time + (File_Time_Stamp (Name_Buffer'Address, Lib_File_Attr)); + + -- ??? One system call here Current_Full_Obj_Stamp := File_Stamp (Current_Full_Obj_Name); if Current_Full_Obj_Stamp (1) = ' ' then -- When the library is readonly always assume object is consistent + -- The call to Is_Writable_File only results in a system call on + -- some systems, but in most cases it has already been computed as + -- part of the call to File_Length above. + + Get_Name_String (Current_Full_Lib_Name); + Name_Buffer (Name_Len + 1) := ASCII.NUL; - if Is_Readonly_Library (Current_Full_Lib_Name) then + if not Is_Writable_File (Name_Buffer'Address, Lib_File_Attr) then Current_Full_Obj_Stamp := Current_Full_Lib_Stamp; elsif Fatal_Err then @@ -2193,10 +2433,6 @@ package body Osint is -- Read data from the file declare - Len : constant Integer := Integer (File_Length (Lib_FD)); - -- Length of source file text. If it doesn't fit in an integer - -- we're probably stuck anyway (>2 gigs of source seems a lot!) - Actual_Len : Integer := 0; Lo : constant Text_Ptr := 0; @@ -2233,7 +2469,7 @@ package body Osint is return Text; - end Read_Library_Info; + end Read_Library_Info_From_Full; ---------------------- -- Read_Source_File -- @@ -2472,21 +2708,23 @@ package body Osint is (N : File_Name_Type; T : File_Type) return Time_Stamp_Type is - Time_Stamp : Time_Stamp_Type; - + File : File_Name_Type; + Attr : aliased File_Attributes; begin if not File_Cache_Enabled then - return File_Stamp (Find_File (N, T)); + Find_File (N, T, File, Attr'Access); + else + Smart_Find_File (N, T, File, Attr); end if; - Time_Stamp := File_Stamp_Hash_Table.Get (N); - - if Time_Stamp (1) = ' ' then - Time_Stamp := File_Stamp (Smart_Find_File (N, T)); - File_Stamp_Hash_Table.Set (N, Time_Stamp); + if File = No_File then + return Empty_Time_Stamp; + else + Get_Name_String (File); + Name_Buffer (Name_Len + 1) := ASCII.NUL; + return OS_Time_To_GNAT_Time + (File_Time_Stamp (Name_Buffer'Address, Attr'Access)); end if; - - return Time_Stamp; end Smart_File_Stamp; --------------------- @@ -2497,21 +2735,38 @@ package body Osint is (N : File_Name_Type; T : File_Type) return File_Name_Type is - Full_File_Name : File_Name_Type; - + File : File_Name_Type; + Attr : File_Attributes; begin - if not File_Cache_Enabled then - return Find_File (N, T); - end if; + Smart_Find_File (N, T, File, Attr); + return File; + end Smart_Find_File; - Full_File_Name := File_Name_Hash_Table.Get (N); + --------------------- + -- Smart_Find_File -- + --------------------- + + procedure Smart_Find_File + (N : File_Name_Type; + T : File_Type; + Found : out File_Name_Type; + Attr : out File_Attributes) + is + Info : File_Info_Cache; - if Full_File_Name = No_File then - Full_File_Name := Find_File (N, T); - File_Name_Hash_Table.Set (N, Full_File_Name); + begin + if not File_Cache_Enabled then + Find_File (N, T, Info.File, Info.Attr'Access); + else + Info := File_Name_Hash_Table.Get (N); + if Info.File = No_File then + Find_File (N, T, Info.File, Info.Attr'Access); + File_Name_Hash_Table.Set (N, Info); + end if; end if; - return Full_File_Name; + Found := Info.File; + Attr := Info.Attr; end Smart_Find_File; ---------------------- @@ -2941,6 +3196,9 @@ package body Osint is -- Package Initialization -- ---------------------------- + procedure Reset_File_Attributes (Attr : System.Address); + pragma Import (C, Reset_File_Attributes, "__gnat_reset_attributes"); + begin Initialization : declare @@ -2956,7 +3214,15 @@ begin "__gnat_get_maximum_file_name_length"); -- Function to get maximum file name length for system + Sizeof_File_Attributes : Integer; + pragma Import (C, Sizeof_File_Attributes, + "__gnat_size_of_file_attributes"); + begin + pragma Assert (Sizeof_File_Attributes <= File_Attributes_Size); + + Reset_File_Attributes (Unknown_Attributes'Address); + Identifier_Character_Set := Get_Default_Identifier_Character_Set; Maximum_File_Name_Length := Get_Maximum_File_Name_Length; diff --git a/gcc/ada/osint.ads b/gcc/ada/osint.ads index a44d4e24b3c..34b3f642fee 100644 --- a/gcc/ada/osint.ads +++ b/gcc/ada/osint.ads @@ -29,6 +29,7 @@ with Namet; use Namet; with Types; use Types; +with System.Storage_Elements; with System.OS_Lib; use System.OS_Lib; with System; use System; @@ -230,6 +231,47 @@ package Osint is -- this routine called with Name set to "gnat" will return "-lgnat-5.02" -- on UNIX and Windows and -lgnat_5_02 on VMS. + --------------------- + -- File attributes -- + --------------------- + -- The following subprograms offer services similar to those found in + -- System.OS_Lib, but with the ability to extra multiple information from + -- a single system call, depending on the system. This can result in fewer + -- system calls when reused. + -- In all these subprograms, the requested value is either read from the + -- File_Attributes parameter (resulting in no system call), or computed + -- from the disk and then cached in the File_Attributes parameter (possibly + -- along with other values). + + type File_Attributes is private; + Unknown_Attributes : constant File_Attributes; + -- A cache for various attributes for a file (length, accessibility,...) + -- This must be initialized to Unknown_Attributes prior to the first call. + + function Is_Directory + (Name : C_File_Name; Attr : access File_Attributes) return Boolean; + function Is_Regular_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean; + function Is_Symbolic_Link + (Name : C_File_Name; Attr : access File_Attributes) return Boolean; + -- Return the type of the file, + + function File_Length + (Name : C_File_Name; Attr : access File_Attributes) return Long_Integer; + -- Return the length (number of bytes) of the file + + function File_Time_Stamp + (Name : C_File_Name; Attr : access File_Attributes) return OS_Time; + -- Return the time stamp of the file + + function Is_Readable_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean; + function Is_Executable_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean; + function Is_Writable_File + (Name : C_File_Name; Attr : access File_Attributes) return Boolean; + -- Return the access rights for the file + ------------------------- -- Search Dir Routines -- ------------------------- @@ -380,6 +422,10 @@ package Osint is -- using Read_Source_File. Calling this routine entails no source file -- directory lookup penalty. + procedure Full_Source_Name + (N : File_Name_Type; + Full_File : out File_Name_Type; + Attr : access File_Attributes); function Full_Source_Name (N : File_Name_Type) return File_Name_Type; function Source_File_Stamp (N : File_Name_Type) return Time_Stamp_Type; -- Returns the full name/time stamp of the source file whose simple name @@ -390,6 +436,8 @@ package Osint is -- The source file directory lookup penalty is incurred every single time -- the routines are called unless you have previously called -- Source_File_Data (Cache => True). See below. + -- The procedural version also returns some file attributes for the ALI + -- file (to save on system calls later on). function Current_File_Index return Int; -- Return the index in its source file of the current main unit @@ -486,6 +534,17 @@ package Osint is -- behaves as if it did not find Lib_File (namely if Fatal_Err is -- False, null is returned). + function Read_Library_Info_From_Full + (Full_Lib_File : File_Name_Type; + Lib_File_Attr : access File_Attributes; + Fatal_Err : Boolean := False) return Text_Buffer_Ptr; + -- Same as Read_Library_Info, except Full_Lib_File must contains the full + -- path to the library file (instead of having Read_Library_Info recompute + -- it). + -- Lib_File_Attr should be an initialized set of attributes for the + -- library file (it can be initialized to Unknown_Attributes, but in + -- general will have been initialized by a previous call to Find_File). + function Full_Library_Info_Name return File_Name_Type; function Full_Object_File_Name return File_Name_Type; -- Returns the full name of the library/object file most recently read @@ -501,14 +560,19 @@ package Osint is -- It is an error to call Current_Object_File_Stamp if -- Opt.Check_Object_Consistency is set to False. + procedure Full_Lib_File_Name + (N : File_Name_Type; + Lib_File : out File_Name_Type; + Attr : out File_Attributes); function Full_Lib_File_Name (N : File_Name_Type) return File_Name_Type; - function Library_File_Stamp (N : File_Name_Type) return Time_Stamp_Type; - -- Returns the full name/time stamp of library file N. N should not include + -- Returns the full name of library file N. N should not include -- path information. Note that if the file cannot be located No_File is -- returned for the first routine and an all blank time stamp is returned -- for the second (this is not an error situation). The full name includes -- the appropriate directory information. The library file directory lookup -- penalty is incurred every single time this routine is called. + -- The procedural version also returns some file attributes for the ALI + -- file (to save on system calls later on). function Lib_File_Name (Source_File : File_Name_Type; @@ -654,4 +718,19 @@ private -- detected, the file being written is deleted, and a fatal error is -- signalled. + File_Attributes_Size : constant Integer := 50; + -- This should be big enough to fit a "struct file_attributes" on any + -- system. It doesn't matter if it is too big (which avoids the need for + -- either mapping the struct exactly or importing the sizeof from C, which + -- would result in dynamic code) + + type File_Attributes is + array (1 .. File_Attributes_Size) + of System.Storage_Elements.Storage_Element; + for File_Attributes'Alignment use Standard'Maximum_Alignment; + + Unknown_Attributes : constant File_Attributes := (others => 0); + -- Will be initialized properly at elaboration (for efficiency later on, + -- avoid function calls every time we want to reset the attributes). + end Osint; diff --git a/gcc/ada/par-ch4.adb b/gcc/ada/par-ch4.adb index f07f54e5098..2bb9d25fcc1 100644 --- a/gcc/ada/par-ch4.adb +++ b/gcc/ada/par-ch4.adb @@ -89,9 +89,6 @@ package body Ch4 is -- prefix. The current token is known to be an apostrophe and the -- following token is known to be RANGE. - procedure Set_Op_Name (Node : Node_Id); - -- Procedure to set name field (Chars) in operator node - ------------------------- -- Bad_Range_Attribute -- ------------------------- @@ -102,51 +99,6 @@ package body Ch4 is Resync_Expression; end Bad_Range_Attribute; - ------------------ - -- Set_Op_Name -- - ------------------ - - procedure Set_Op_Name (Node : Node_Id) is - type Name_Of_Type is array (N_Op) of Name_Id; - Name_Of : constant Name_Of_Type := Name_Of_Type'( - N_Op_And => Name_Op_And, - N_Op_Or => Name_Op_Or, - N_Op_Xor => Name_Op_Xor, - N_Op_Eq => Name_Op_Eq, - N_Op_Ne => Name_Op_Ne, - N_Op_Lt => Name_Op_Lt, - N_Op_Le => Name_Op_Le, - N_Op_Gt => Name_Op_Gt, - N_Op_Ge => Name_Op_Ge, - N_Op_Add => Name_Op_Add, - N_Op_Subtract => Name_Op_Subtract, - N_Op_Concat => Name_Op_Concat, - N_Op_Multiply => Name_Op_Multiply, - N_Op_Divide => Name_Op_Divide, - N_Op_Mod => Name_Op_Mod, - N_Op_Rem => Name_Op_Rem, - N_Op_Expon => Name_Op_Expon, - N_Op_Plus => Name_Op_Add, - N_Op_Minus => Name_Op_Subtract, - N_Op_Abs => Name_Op_Abs, - N_Op_Not => Name_Op_Not, - - -- We don't really need these shift operators, since they never - -- appear as operators in the source, but the path of least - -- resistance is to put them in (the aggregate must be complete) - - N_Op_Rotate_Left => Name_Rotate_Left, - N_Op_Rotate_Right => Name_Rotate_Right, - N_Op_Shift_Left => Name_Shift_Left, - N_Op_Shift_Right => Name_Shift_Right, - N_Op_Shift_Right_Arithmetic => Name_Shift_Right_Arithmetic); - - begin - if Nkind (Node) in N_Op then - Set_Chars (Node, Name_Of (Nkind (Node))); - end if; - end Set_Op_Name; - -------------------------- -- 4.1 Name (also 6.4) -- -------------------------- @@ -1600,10 +1552,9 @@ package body Ch4 is end if; Node2 := Node1; - Node1 := New_Node (Logical_Op, Op_Location); + Node1 := New_Op_Node (Logical_Op, Op_Location); Set_Left_Opnd (Node1, Node2); Set_Right_Opnd (Node1, P_Relation); - Set_Op_Name (Node1); exit when Token not in Token_Class_Logop; end loop; @@ -1704,10 +1655,9 @@ package body Ch4 is end if; Node2 := Node1; - Node1 := New_Node (Logical_Op, Op_Location); + Node1 := New_Op_Node (Logical_Op, Op_Location); Set_Left_Opnd (Node1, Node2); Set_Right_Opnd (Node1, P_Relation); - Set_Op_Name (Node1); exit when Token not in Token_Class_Logop; end loop; @@ -1768,9 +1718,8 @@ package body Ch4 is -- P_Relational_Operator also parses the IN and NOT IN operations. Optok := Token_Ptr; - Node2 := New_Node (P_Relational_Operator, Optok); + Node2 := New_Op_Node (P_Relational_Operator, Optok); Set_Left_Opnd (Node2, Node1); - Set_Op_Name (Node2); -- Case of IN or NOT IN @@ -1881,18 +1830,17 @@ package body Ch4 is Style.Check_Exponentiation_Operator; end if; - Node2 := New_Node (N_Op_Expon, Token_Ptr); + Node2 := New_Op_Node (N_Op_Expon, Token_Ptr); Scan; -- past ** Set_Left_Opnd (Node2, Node1); Set_Right_Opnd (Node2, P_Primary); - Set_Op_Name (Node2); Node1 := Node2; end if; loop exit when Token not in Token_Class_Mulop; Tokptr := Token_Ptr; - Node2 := New_Node (P_Multiplying_Operator, Tokptr); + Node2 := New_Op_Node (P_Multiplying_Operator, Tokptr); if Style_Check then Style.Check_Binary_Operator; @@ -1901,14 +1849,13 @@ package body Ch4 is Scan; -- past operator Set_Left_Opnd (Node2, Node1); Set_Right_Opnd (Node2, P_Factor); - Set_Op_Name (Node2); Node1 := Node2; end loop; loop exit when Token not in Token_Class_Binary_Addop; Tokptr := Token_Ptr; - Node2 := New_Node (P_Binary_Adding_Operator, Tokptr); + Node2 := New_Op_Node (P_Binary_Adding_Operator, Tokptr); if Style_Check then Style.Check_Binary_Operator; @@ -1917,7 +1864,6 @@ package body Ch4 is Scan; -- past operator Set_Left_Opnd (Node2, Node1); Set_Right_Opnd (Node2, P_Term); - Set_Op_Name (Node2); Node1 := Node2; end loop; @@ -1931,7 +1877,7 @@ package body Ch4 is if Token in Token_Class_Unary_Addop then Tokptr := Token_Ptr; - Node1 := New_Node (P_Unary_Adding_Operator, Tokptr); + Node1 := New_Op_Node (P_Unary_Adding_Operator, Tokptr); if Style_Check then Style.Check_Unary_Plus_Or_Minus; @@ -1939,7 +1885,6 @@ package body Ch4 is Scan; -- past operator Set_Right_Opnd (Node1, P_Term); - Set_Op_Name (Node1); else Node1 := P_Term; end if; @@ -1981,12 +1926,11 @@ package body Ch4 is loop exit when Token not in Token_Class_Binary_Addop; Tokptr := Token_Ptr; - Node2 := New_Node (P_Binary_Adding_Operator, Tokptr); + Node2 := New_Op_Node (P_Binary_Adding_Operator, Tokptr); Scan; -- past operator Set_Left_Opnd (Node2, Node1); Node1 := P_Term; Set_Right_Opnd (Node2, Node1); - Set_Op_Name (Node2); -- Check if we're still concatenating string literals @@ -2214,11 +2158,10 @@ package body Ch4 is loop exit when Token not in Token_Class_Mulop; Tokptr := Token_Ptr; - Node2 := New_Node (P_Multiplying_Operator, Tokptr); + Node2 := New_Op_Node (P_Multiplying_Operator, Tokptr); Scan; -- past operator Set_Left_Opnd (Node2, Node1); Set_Right_Opnd (Node2, P_Factor); - Set_Op_Name (Node2); Node1 := Node2; end loop; @@ -2239,7 +2182,7 @@ package body Ch4 is begin if Token = Tok_Abs then - Node1 := New_Node (N_Op_Abs, Token_Ptr); + Node1 := New_Op_Node (N_Op_Abs, Token_Ptr); if Style_Check then Style.Check_Abs_Not; @@ -2247,11 +2190,10 @@ package body Ch4 is Scan; -- past ABS Set_Right_Opnd (Node1, P_Primary); - Set_Op_Name (Node1); return Node1; elsif Token = Tok_Not then - Node1 := New_Node (N_Op_Not, Token_Ptr); + Node1 := New_Op_Node (N_Op_Not, Token_Ptr); if Style_Check then Style.Check_Abs_Not; @@ -2259,18 +2201,16 @@ package body Ch4 is Scan; -- past NOT Set_Right_Opnd (Node1, P_Primary); - Set_Op_Name (Node1); return Node1; else Node1 := P_Primary; if Token = Tok_Double_Asterisk then - Node2 := New_Node (N_Op_Expon, Token_Ptr); + Node2 := New_Op_Node (N_Op_Expon, Token_Ptr); Scan; -- past ** Set_Left_Opnd (Node2, Node1); Set_Right_Opnd (Node2, P_Primary); - Set_Op_Name (Node2); return Node2; else return Node1; diff --git a/gcc/ada/prj-err.adb b/gcc/ada/prj-err.adb index 8e0d5627a67..3728c9e44b0 100644 --- a/gcc/ada/prj-err.adb +++ b/gcc/ada/prj-err.adb @@ -23,8 +23,9 @@ -- -- ------------------------------------------------------------------------------ -with Output; use Output; -with Stringt; use Stringt; +with Err_Vars; +with Output; use Output; +with Stringt; use Stringt; package body Prj.Err is @@ -117,7 +118,13 @@ package body Prj.Err is if Flags.Report_Error /= null then Flags.Report_Error (Project, - Is_Warning => Msg (Msg'First) = '?' or else Msg (Msg'First) = '<'); + Is_Warning => + Msg (Msg'First) = '?' + or else (Msg (Msg'First) = '<' + and then Err_Vars.Error_Msg_Warn) + or else (Msg (Msg'First) = '\' + and then Msg (Msg'First + 1) = '<' + and then Err_Vars.Error_Msg_Warn)); end if; end Error_Msg; diff --git a/gcc/ada/prj-ext.adb b/gcc/ada/prj-ext.adb index 9c9707c1cfa..8c7a5d95d96 100644 --- a/gcc/ada/prj-ext.adb +++ b/gcc/ada/prj-ext.adb @@ -26,6 +26,7 @@ with System.OS_Lib; use System.OS_Lib; with Hostparm; with Makeutl; use Makeutl; +with Opt; with Osint; use Osint; with Prj.Tree; use Prj.Tree; with Sdefault; @@ -212,7 +213,9 @@ package body Prj.Ext is declare New_Dir : constant String := - Normalize_Pathname (Name_Buffer (First .. Last)); + Normalize_Pathname + (Name_Buffer (First .. Last), + Resolve_Links => Opt.Follow_Links_For_Dirs); begin -- If the absolute path was resolved and is different from diff --git a/gcc/ada/prj-nmsc.adb b/gcc/ada/prj-nmsc.adb index cec5e6b0a59..5e76bce58ac 100644 --- a/gcc/ada/prj-nmsc.adb +++ b/gcc/ada/prj-nmsc.adb @@ -4707,121 +4707,82 @@ package body Prj.Nmsc is Removed : Boolean := False) is Directory : constant String := Get_Name_String (From); - Element : String_Element; + + procedure Add_To_Or_Remove_From_List + (Path_Id : Name_Id; + Display_Path_Id : Name_Id); + -- When Removed = False, the directory Path_Id to the list of + -- source_dirs if not already in the list. When Removed = True, + -- removed directory Path_Id if in the list. procedure Recursive_Find_Dirs (Path : Name_Id); -- Find all the subdirectories (recursively) of Path and add them -- to the list of source directories of the project. - ------------------------- - -- Recursive_Find_Dirs -- - ------------------------- - - procedure Recursive_Find_Dirs (Path : Name_Id) is - Dir : Dir_Type; - Name : String (1 .. 250); - Last : Natural; - List : String_List_Id; - Prev : String_List_Id; - Rank_List : Number_List_Index; - Prev_Rank : Number_List_Index; - Element : String_Element; - Found : Boolean := False; - - Non_Canonical_Path : Name_Id := No_Name; - Canonical_Path : Name_Id := No_Name; - - The_Path : constant String := - Normalize_Pathname - (Get_Name_String (Path), - Directory => - Get_Name_String (Project.Directory.Display_Name), - Resolve_Links => Opt.Follow_Links_For_Dirs) & - Directory_Separator; - - The_Path_Last : constant Natural := - Compute_Directory_Last (The_Path); + -------------------------------- + -- Add_To_Or_Remove_From_List -- + -------------------------------- + + procedure Add_To_Or_Remove_From_List + (Path_Id : Name_Id; + Display_Path_Id : Name_Id) + is + List : String_List_Id; + Prev : String_List_Id; + Rank_List : Number_List_Index; + Prev_Rank : Number_List_Index; + Element : String_Element; begin - Name_Len := The_Path_Last - The_Path'First + 1; - Name_Buffer (1 .. Name_Len) := - The_Path (The_Path'First .. The_Path_Last); - Non_Canonical_Path := Name_Find; - Canonical_Path := - Name_Id (Canonical_Case_File_Name (Non_Canonical_Path)); - - -- To avoid processing the same directory several times, check - -- if the directory is already in Recursive_Dirs. If it is, then - -- there is nothing to do, just return. If it is not, put it there - -- and continue recursive processing. - - if not Removed then - if Recursive_Dirs.Get (Visited, Canonical_Path) then - return; - else - Recursive_Dirs.Set (Visited, Canonical_Path, True); - end if; - end if; - - -- Check if directory is already in list - - List := Project.Source_Dirs; - Prev := Nil_String; - Rank_List := Project.Source_Dir_Ranks; + Prev := Nil_String; Prev_Rank := No_Number_List; + List := Project.Source_Dirs; + Rank_List := Project.Source_Dir_Ranks; while List /= Nil_String loop Element := Data.Tree.String_Elements.Table (List); - - if Element.Value /= No_Name then - Found := Element.Value = Canonical_Path; - exit when Found; - end if; - + exit when Element.Value = Path_Id; Prev := List; List := Element.Next; Prev_Rank := Rank_List; - Rank_List := Data.Tree.Number_Lists.Table (Rank_List).Next; + Rank_List := Data.Tree.Number_Lists.Table (Prev_Rank).Next; end loop; - -- If directory is not already in list, put it there + -- The directory is in the list if List is not Nil_String - if (not Removed) and (not Found) then + if not Removed and then List = Nil_String then if Current_Verbosity = High then - Write_Str (" "); - Write_Line (The_Path (The_Path'First .. The_Path_Last)); + Write_Str (" Adding Source Dir="); + Write_Line (Get_Name_String (Path_Id)); end if; String_Element_Table.Increment_Last (Data.Tree.String_Elements); Element := - (Value => Canonical_Path, - Display_Value => Non_Canonical_Path, + (Value => Path_Id, + Index => 0, + Display_Value => Display_Path_Id, Location => No_Location, Flag => False, - Next => Nil_String, - Index => 0); + Next => Nil_String); Number_List_Table.Increment_Last (Data.Tree.Number_Lists); - -- Case of first source directory - if Last_Source_Dir = Nil_String then + + -- This is the first source directory + Project.Source_Dirs := String_Element_Table.Last (Data.Tree.String_Elements); Project.Source_Dir_Ranks := Number_List_Table.Last (Data.Tree.Number_Lists); - -- Here we already have source directories - else - -- Link the previous last to the new one + -- We already have source directories, link the previous + -- last to the new one. - Data.Tree.String_Elements.Table - (Last_Source_Dir).Next := + Data.Tree.String_Elements.Table (Last_Source_Dir).Next := String_Element_Table.Last (Data.Tree.String_Elements); - Data.Tree.Number_Lists.Table - (Last_Src_Dir_Rank).Next := + Data.Tree.Number_Lists.Table (Last_Src_Dir_Rank).Next := Number_List_Table.Last (Data.Tree.Number_Lists); - end if; -- And register this source directory as the new last @@ -4834,12 +4795,16 @@ package body Prj.Nmsc is Data.Tree.Number_Lists.Table (Last_Src_Dir_Rank) := (Number => Rank, Next => No_Number_List); - elsif Removed and Found then + elsif Removed and then List /= Nil_String then + + -- Remove source dir, if present + if Prev = Nil_String then Project.Source_Dirs := Data.Tree.String_Elements.Table (List).Next; Project.Source_Dir_Ranks := Data.Tree.Number_Lists.Table (Rank_List).Next; + else Data.Tree.String_Elements.Table (Prev).Next := Data.Tree.String_Elements.Table (List).Next; @@ -4847,10 +4812,59 @@ package body Prj.Nmsc is Data.Tree.Number_Lists.Table (Rank_List).Next; end if; end if; + end Add_To_Or_Remove_From_List; + + ------------------------- + -- Recursive_Find_Dirs -- + ------------------------- + + procedure Recursive_Find_Dirs (Path : Name_Id) is + Dir : Dir_Type; + Name : String (1 .. 250); + Last : Natural; - -- Now look for subdirectories. We do that even when this - -- directory is already in the list, because some of its - -- subdirectories may not be in the list yet. + Non_Canonical_Path : Name_Id := No_Name; + Canonical_Path : Name_Id := No_Name; + + The_Path : constant String := + Normalize_Pathname + (Get_Name_String (Path), + Directory => + Get_Name_String (Project.Directory.Display_Name), + Resolve_Links => Opt.Follow_Links_For_Dirs) & + Directory_Separator; + + The_Path_Last : constant Natural := + Compute_Directory_Last (The_Path); + + begin + Name_Len := The_Path_Last - The_Path'First + 1; + Name_Buffer (1 .. Name_Len) := + The_Path (The_Path'First .. The_Path_Last); + Non_Canonical_Path := Name_Find; + Canonical_Path := + Name_Id (Canonical_Case_File_Name (Non_Canonical_Path)); + + -- To avoid processing the same directory several times, check + -- if the directory is already in Recursive_Dirs. If it is, then + -- there is nothing to do, just return. If it is not, put it there + -- and continue recursive processing. + + if not Removed then + if Recursive_Dirs.Get (Visited, Canonical_Path) then + return; + else + Recursive_Dirs.Set (Visited, Canonical_Path, True); + end if; + end if; + + Add_To_Or_Remove_From_List + (Path_Id => Canonical_Path, + Display_Path_Id => Non_Canonical_Path); + + -- Now look for subdirectories. Do that even when this directory + -- is already in the list, because some of its subdirectories may + -- not be in the list yet. Open (Dir, The_Path (The_Path'First .. The_Path_Last)); @@ -4870,12 +4884,14 @@ package body Prj.Nmsc is declare Path_Name : constant String := - Normalize_Pathname - (Name => Name (1 .. Last), - Directory => - The_Path (The_Path'First .. The_Path_Last), - Resolve_Links => Opt.Follow_Links_For_Dirs, - Case_Sensitive => True); + Normalize_Pathname + (Name => Name (1 .. Last), + Directory => + The_Path + (The_Path'First .. The_Path_Last), + Resolve_Links => + Opt.Follow_Links_For_Dirs, + Case_Sensitive => True); begin if Is_Directory (Path_Name) then @@ -4945,7 +4961,8 @@ package body Prj.Nmsc is Directory => Get_Name_String (Project.Directory.Display_Name), - Resolve_Links => False, + Resolve_Links => + Opt.Follow_Links_For_Dirs, Case_Sensitive => True); begin @@ -4987,10 +5004,6 @@ package body Prj.Nmsc is else declare Path_Name : Path_Information; - List : String_List_Id; - Prev : String_List_Id; - Rank_List : Number_List_Index; - Prev_Rank : Number_List_Index; Dir_Exists : Boolean; begin @@ -5019,8 +5032,16 @@ package body Prj.Nmsc is else declare - Path : constant String := - Get_Name_String (Path_Name.Name); + Path : constant String := + Normalize_Pathname + (Name => + Get_Name_String (Path_Name.Name), + Directory => + Get_Name_String (Project.Directory.Name), + Resolve_Links => Opt.Follow_Links_For_Dirs, + Case_Sensitive => True) & + Directory_Separator; + Last_Path : constant Natural := Compute_Directory_Last (Path); Path_Id : Name_Id; @@ -5036,113 +5057,16 @@ package body Prj.Nmsc is Name_Len := 0; Add_Str_To_Name_Buffer (Path (Path'First .. Last_Path)); Path_Id := Name_Find; + Name_Len := 0; Add_Str_To_Name_Buffer (Display_Path (Display_Path'First .. Last_Display_Path)); Display_Path_Id := Name_Find; - -- Check if the directory is already in the list - - Prev := Nil_String; - Prev_Rank := No_Number_List; - - -- Look for source dir in current list - - List := Project.Source_Dirs; - Rank_List := Project.Source_Dir_Ranks; - while List /= Nil_String loop - Element := Data.Tree.String_Elements.Table (List); - exit when Element.Value = Path_Id; - Prev := List; - List := Element.Next; - Prev_Rank := Rank_List; - Rank_List := - Data.Tree.Number_Lists.Table (Prev_Rank).Next; - end loop; - - -- The directory is in the list if List is not Nil_String - - if not Removed then - - -- As it is an existing directory, we add it to the - -- list of directories, if not already in the list. - - if List = Nil_String then - String_Element_Table.Increment_Last - (Data.Tree.String_Elements); - Element := - (Value => Path_Id, - Index => 0, - Display_Value => Display_Path_Id, - Location => No_Location, - Flag => False, - Next => Nil_String); - Number_List_Table.Increment_Last - (Data.Tree.Number_Lists); - - if Last_Source_Dir = Nil_String then - - -- This is the first source directory - - Project.Source_Dirs := - String_Element_Table.Last - (Data.Tree.String_Elements); - Project.Source_Dir_Ranks := - Number_List_Table.Last - (Data.Tree.Number_Lists); - - else - -- We already have source directories, link the - -- previous last to the new one. - - Data.Tree.String_Elements.Table - (Last_Source_Dir).Next := - String_Element_Table.Last - (Data.Tree.String_Elements); - Data.Tree.Number_Lists.Table - (Last_Src_Dir_Rank).Next := - Number_List_Table.Last - (Data.Tree.Number_Lists); - - end if; - - -- And register this source directory as the new - -- last. - - Last_Source_Dir := - String_Element_Table.Last - (Data.Tree.String_Elements); - Data.Tree.String_Elements.Table - (Last_Source_Dir) := Element; - Last_Src_Dir_Rank := - Number_List_Table.Last - (Data.Tree.Number_Lists); - Data.Tree.Number_Lists.Table - (Last_Src_Dir_Rank) := - (Number => Rank, Next => No_Number_List); - end if; - - else - -- Remove source dir, if present - - if List /= Nil_String then - -- Source dir was found, remove it from the list - - if Prev = Nil_String then - Project.Source_Dirs := - Data.Tree.String_Elements.Table (List).Next; - Project.Source_Dir_Ranks := - Data.Tree.Number_Lists.Table (Rank_List).Next; - - else - Data.Tree.String_Elements.Table (Prev).Next := - Data.Tree.String_Elements.Table (List).Next; - Data.Tree.Number_Lists.Table (Prev_Rank).Next := - Data.Tree.Number_Lists.Table (Rank_List).Next; - end if; - end if; - end if; + Add_To_Or_Remove_From_List + (Path_Id => Path_Id, + Display_Path_Id => Display_Path_Id); end; end if; end; diff --git a/gcc/ada/prj-part.adb b/gcc/ada/prj-part.adb index 1ed78ab227b..7702f540930 100644 --- a/gcc/ada/prj-part.adb +++ b/gcc/ada/prj-part.adb @@ -485,19 +485,27 @@ package body Prj.Part is return; end if; - Parse_Single_Project - (In_Tree => In_Tree, - Project => Project, - Extends_All => Dummy, - Path_Name => Path_Name, - Extended => False, - From_Extended => None, - In_Limited => False, - Packages_To_Check => Packages_To_Check, - Depth => 0, - Current_Dir => Current_Directory, - Is_Config_File => Is_Config_File, - Flags => Flags); + begin + Parse_Single_Project + (In_Tree => In_Tree, + Project => Project, + Extends_All => Dummy, + Path_Name => Path_Name, + Extended => False, + From_Extended => None, + In_Limited => False, + Packages_To_Check => Packages_To_Check, + Depth => 0, + Current_Dir => Current_Directory, + Is_Config_File => Is_Config_File, + Flags => Flags); + + exception + when Types.Unrecoverable_Error => + -- Unrecoverable_Error is raised when a line is too long. + -- A meaningful error message will be displayed later. + Project := Empty_Node; + end; -- If Project is an extending-all project, create the eventual -- virtual extending projects and check that there are no illegally diff --git a/gcc/ada/prj-tree.adb b/gcc/ada/prj-tree.adb index 4823a988d6c..df6e5acb6cf 100644 --- a/gcc/ada/prj-tree.adb +++ b/gcc/ada/prj-tree.adb @@ -23,10 +23,11 @@ -- -- ------------------------------------------------------------------------------ -with Ada.Unchecked_Deallocation; with Osint; use Osint; with Prj.Err; +with Ada.Unchecked_Deallocation; + package body Prj.Tree is Node_With_Comments : constant array (Project_Node_Kind) of Boolean := @@ -1000,6 +1001,8 @@ package body Prj.Tree is if Proj /= null then Project_Node_Table.Free (Proj.Project_Nodes); Projects_Htable.Reset (Proj.Projects_HT); + Name_To_Name_HTable.Reset (Proj.External_References); + Free (Proj.Project_Path); Unchecked_Free (Proj); end if; end Free; diff --git a/gcc/ada/raise-gcc.c b/gcc/ada/raise-gcc.c index 1d9efb93b7f..3589bc5dfd1 100644 --- a/gcc/ada/raise-gcc.c +++ b/gcc/ada/raise-gcc.c @@ -56,6 +56,14 @@ typedef char bool; #include "adaint.h" #include "raise.h" +#ifdef __APPLE__ +/* On MacOS X, versions older than 10.5 don't export _Unwind_GetIPInfo. */ +#undef HAVE_GETIPINFO +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 +#define HAVE_GETIPINFO 1 +#endif +#endif + /* The names of a couple of "standard" routines for unwinding/propagation actually vary depending on the underlying GCC scheme for exception handling (SJLJ or DWARF). We need a consistently named interface to import from @@ -501,7 +509,14 @@ typedef struct static void db_region_for (region_descriptor *region, _Unwind_Context *uw_context) { - _Unwind_Ptr ip = _Unwind_GetIP (uw_context) - 1; + int ip_before_insn = 0; +#ifdef HAVE_GETIPINFO + _Unwind_Ptr ip = _Unwind_GetIPInfo (uw_context, &ip_before_insn); +#else + _Unwind_Ptr ip = _Unwind_GetIP (uw_context); +#endif + if (!ip_before_insn) + ip--; if (! (db_accepted_codes () & DB_REGIONS)) return; @@ -631,7 +646,14 @@ typedef struct static void db_action_for (action_descriptor *action, _Unwind_Context *uw_context) { - _Unwind_Ptr ip = _Unwind_GetIP (uw_context) - 1; + int ip_before_insn = 0; +#ifdef HAVE_GETIPINFO + _Unwind_Ptr ip = _Unwind_GetIPInfo (uw_context, &ip_before_insn); +#else + _Unwind_Ptr ip = _Unwind_GetIP (uw_context); +#endif + if (!ip_before_insn) + ip--; db (DB_ACTIONS, "For ip @ 0x%08x => ", ip); @@ -670,14 +692,6 @@ db_action_for (action_descriptor *action, _Unwind_Context *uw_context) There are two variants of this routine, depending on the underlying mechanism (DWARF/SJLJ), which account for differences in the tables. */ -#ifdef __APPLE__ -/* On MacOS X, versions older than 10.5 don't export _Unwind_GetIPInfo. */ -#undef HAVE_GETIPINFO -#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 1050 -#define HAVE_GETIPINFO 1 -#endif -#endif - #ifdef __USING_SJLJ_EXCEPTIONS__ #define __builtin_eh_return_data_regno(x) x diff --git a/gcc/ada/s-crtl.ads b/gcc/ada/s-crtl.ads index 5a9902dd657..f013a418fcb 100644 --- a/gcc/ada/s-crtl.ads +++ b/gcc/ada/s-crtl.ads @@ -202,4 +202,7 @@ package System.CRTL is function write (fd : int; buffer : chars; nbytes : int) return int; pragma Import (C, write, "write"); + function strerror (errno : int) return chars; + pragma Import (C, strerror, "strerror"); + end System.CRTL; diff --git a/gcc/ada/s-fileio.adb b/gcc/ada/s-fileio.adb index df45003cd1a..f93fee25e33 100644 --- a/gcc/ada/s-fileio.adb +++ b/gcc/ada/s-fileio.adb @@ -31,7 +31,10 @@ with Ada.Finalization; use Ada.Finalization; with Ada.IO_Exceptions; use Ada.IO_Exceptions; +with Ada.Unchecked_Conversion; + with Interfaces.C; +with Interfaces.C.Strings; use Interfaces.C.Strings; with Interfaces.C_Streams; use Interfaces.C_Streams; with System.CRTL; @@ -48,7 +51,7 @@ package body System.File_IO is package SSL renames System.Soft_Links; use type Interfaces.C.int; - use type System.CRTL.size_t; + use type CRTL.size_t; ---------------------- -- Global Variables -- @@ -126,6 +129,23 @@ package body System.File_IO is -- call to fopen or freopen. Amethod is the character designating -- the access method from the Access_Method field of the FCB. + function Errno_Message + (Errno : Integer := OS_Lib.Errno) return String; + function Errno_Message + (Name : String; + Errno : Integer := OS_Lib.Errno) return String; + -- Return a message suitable for "raise ... with Errno_Message (...)". + -- Errno defaults to the current errno, but should be passed explicitly if + -- there is significant code in between the call that sets errno and the + -- call to Errno_Message, in case that code also sets errno. The version + -- with Name includes that file name in the message. + + procedure Raise_Device_Error + (File : AFCB_Ptr; Errno : Integer := OS_Lib.Errno); + pragma No_Return (Raise_Device_Error); + -- Clear error indication on File and raise Device_Error with an exception + -- message providing errno information. + ---------------- -- Append_Set -- ---------------- @@ -134,7 +154,7 @@ package body System.File_IO is begin if File.Mode = Append_File then if fseek (File.Stream, 0, SEEK_END) /= 0 then - raise Device_Error; + Raise_Device_Error (File); end if; end if; end Append_Set; @@ -174,7 +194,7 @@ package body System.File_IO is procedure Check_File_Open (File : AFCB_Ptr) is begin if File = null then - raise Status_Error; + raise Status_Error with "file not open"; end if; end Check_File_Open; @@ -185,9 +205,9 @@ package body System.File_IO is procedure Check_Read_Status (File : AFCB_Ptr) is begin if File = null then - raise Status_Error; + raise Status_Error with "file not open"; elsif File.Mode > Inout_File then - raise Mode_Error; + raise Mode_Error with "file not readable"; end if; end Check_Read_Status; @@ -198,9 +218,9 @@ package body System.File_IO is procedure Check_Write_Status (File : AFCB_Ptr) is begin if File = null then - raise Status_Error; + raise Status_Error with "file not open"; elsif File.Mode = In_File then - raise Mode_Error; + raise Mode_Error with "file not writable"; end if; end Check_Write_Status; @@ -212,6 +232,7 @@ package body System.File_IO is Close_Status : int := 0; Dup_Strm : Boolean := False; File : AFCB_Ptr renames File_Ptr.all; + Errno : Integer; begin -- Take a task lock, to protect the global data value Open_Files @@ -223,15 +244,14 @@ package body System.File_IO is -- Sever the association between the given file and its associated -- external file. The given file is left closed. Do not perform system - -- closes on the standard input, output and error files and also do - -- not attempt to close a stream that does not exist (signalled by a - -- null stream value -- happens in some error situations). + -- closes on the standard input, output and error files and also do not + -- attempt to close a stream that does not exist (signalled by a null + -- stream value -- happens in some error situations). - if not File.Is_System_File - and then File.Stream /= NULL_Stream - then - -- Do not do an fclose if this is a shared file and there is - -- at least one other instance of the stream that is open. + if not File.Is_System_File and then File.Stream /= NULL_Stream then + + -- Do not do an fclose if this is a shared file and there is at least + -- one other instance of the stream that is open. if File.Shared_Status = Yes then declare @@ -240,9 +260,7 @@ package body System.File_IO is begin P := Open_Files; while P /= null loop - if P /= File - and then File.Stream = P.Stream - then + if P /= File and then File.Stream = P.Stream then Dup_Strm := True; exit; end if; @@ -256,6 +274,10 @@ package body System.File_IO is if not Dup_Strm then Close_Status := fclose (File.Stream); + + if Close_Status /= 0 then + Errno := OS_Lib.Errno; + end if; end if; end if; @@ -284,7 +306,7 @@ package body System.File_IO is File := null; if Close_Status /= 0 then - raise Device_Error; + Raise_Device_Error (null, Errno); end if; SSL.Unlock_Task.all; @@ -301,11 +323,12 @@ package body System.File_IO is procedure Delete (File_Ptr : access AFCB_Ptr) is File : AFCB_Ptr renames File_Ptr.all; + begin Check_File_Open (File); if not File.Is_Regular_File then - raise Use_Error; + raise Use_Error with "cannot delete non-regular file"; end if; declare @@ -314,12 +337,12 @@ package body System.File_IO is begin Close (File_Ptr); - -- Now unlink the external file. Note that we use the full name - -- in this unlink, because the working directory may have changed - -- since we did the open, and we want to unlink the right file! + -- Now unlink the external file. Note that we use the full name in + -- this unlink, because the working directory may have changed since + -- we did the open, and we want to unlink the right file! if unlink (Filename'Address) = -1 then - raise Use_Error; + raise Use_Error with Errno_Message; end if; end; end Delete; @@ -347,13 +370,45 @@ package body System.File_IO is end if; end End_Of_File; + ------------------- + -- Errno_Message -- + ------------------- + + function Errno_Message (Errno : Integer := OS_Lib.Errno) return String is + pragma Warnings (Off); + function To_Chars_Ptr is + new Ada.Unchecked_Conversion (System.Address, chars_ptr); + -- On VMS, the compiler warns because System.Address is 64 bits, but + -- chars_ptr is 32 bits. It should be safe, though, because strerror + -- will return a 32-bit pointer. + pragma Warnings (On); + + Message : constant chars_ptr := + To_Chars_Ptr (CRTL.strerror (Errno)); + + begin + if Message = Null_Ptr then + return "errno =" & Errno'Img; + else + return Value (Message); + end if; + end Errno_Message; + + function Errno_Message + (Name : String; + Errno : Integer := OS_Lib.Errno) return String + is + begin + return Name & ": " & String'(Errno_Message (Errno)); + end Errno_Message; + -------------- -- Finalize -- -------------- - -- Note: we do not need to worry about locking against multiple task - -- access in this routine, since it is called only from the environment - -- task just before terminating execution. + -- Note: we do not need to worry about locking against multiple task access + -- in this routine, since it is called only from the environment task just + -- before terminating execution. procedure Finalize (V : in out File_IO_Clean_Up_Type) is pragma Warnings (Off, V); @@ -369,8 +424,8 @@ package body System.File_IO is SSL.Lock_Task.all; - -- First close all open files (the slightly complex form of this loop - -- is required because Close as a side effect nulls out its argument) + -- First close all open files (the slightly complex form of this loop is + -- required because Close as a side effect nulls out its argument). Fptr1 := Open_Files; while Fptr1 /= null loop @@ -379,9 +434,9 @@ package body System.File_IO is Fptr1 := Fptr2; end loop; - -- Now unlink all temporary files. We do not bother to free the - -- blocks because we are just about to terminate the program. We - -- also ignore any errors while attempting these unlink operations. + -- Now unlink all temporary files. We do not bother to free the blocks + -- because we are just about to terminate the program. We also ignore + -- any errors while attempting these unlink operations. while Temp_Files /= null loop Discard := unlink (Temp_Files.Name'Address); @@ -404,10 +459,8 @@ package body System.File_IO is begin Check_Write_Status (File); - if fflush (File.Stream) = 0 then - return; - else - raise Device_Error; + if fflush (File.Stream) /= 0 then + Raise_Device_Error (File); end if; end Flush; @@ -429,20 +482,20 @@ package body System.File_IO is -- you can reset to earlier points in the file. The caller must use the -- Append_Set routine to deal with the necessary positioning. - -- Note: in several cases, the fopen mode used allows reading and - -- writing, but the setting of the Ada mode is more restrictive. For - -- instance, Create in In_File mode uses "w+" which allows writing, - -- but the Ada mode In_File will cause any write operations to be - -- rejected with Mode_Error in any case. + -- Note: in several cases, the fopen mode used allows reading and writing, + -- but the setting of the Ada mode is more restrictive. For instance, + -- Create in In_File mode uses "w+" which allows writing, but the Ada mode + -- In_File will cause any write operations to be rejected with Mode_Error + -- in any case. - -- Note: for the Out_File/Open cases for other than the Direct_IO case, - -- an initial call will be made by the caller to first open the file in - -- "r" mode to be sure that it exists. The real open, in "w" mode, will - -- then destroy this file. This is peculiar, but that's what Ada semantics - -- require and the ACVT tests insist on! + -- Note: for the Out_File/Open cases for other than the Direct_IO case, an + -- initial call will be made by the caller to first open the file in "r" + -- mode to be sure that it exists. The real open, in "w" mode, will then + -- destroy this file. This is peculiar, but that's what Ada semantics + -- require and the ACATS tests insist on! - -- If text file translation is required, then either b or t is - -- added to the mode, depending on the setting of Text. + -- If text file translation is required, then either "b" or "t" is appended + -- to the mode, depending on the setting of Text. procedure Fopen_Mode (Mode : File_Mode; @@ -510,7 +563,7 @@ package body System.File_IO is function Form (File : AFCB_Ptr) return String is begin if File = null then - raise Status_Error; + raise Status_Error with "Form: file not open"; else return File.Form.all (1 .. File.Form'Length - 1); end if; @@ -523,8 +576,7 @@ package body System.File_IO is function Form_Boolean (Form : String; Keyword : String; - Default : Boolean) - return Boolean + Default : Boolean) return Boolean is V1, V2 : Natural; pragma Unreferenced (V2); @@ -542,7 +594,7 @@ package body System.File_IO is return False; else - raise Use_Error; + raise Use_Error with "invalid Form"; end if; end Form_Boolean; @@ -553,8 +605,7 @@ package body System.File_IO is function Form_Integer (Form : String; Keyword : String; - Default : Integer) - return Integer + Default : Integer) return Integer is V1, V2 : Natural; V : Integer; @@ -570,13 +621,13 @@ package body System.File_IO is for J in V1 .. V2 loop if Form (J) not in '0' .. '9' then - raise Use_Error; + raise Use_Error with "invalid Form"; else V := V * 10 + Character'Pos (Form (J)) - Character'Pos ('0'); end if; if V > 999_999 then - raise Use_Error; + raise Use_Error with "invalid Form"; end if; end loop; @@ -593,11 +644,9 @@ package body System.File_IO is Keyword : String; Start : out Natural; Stop : out Natural) - is + is Klen : constant Integer := Keyword'Length; - -- Start of processing for Form_Parameter - begin for J in Form'First + Klen .. Form'Last - 1 loop if Form (J) = '=' @@ -663,6 +712,7 @@ package body System.File_IO is begin status := setvbuf (File.Stream, Null_Address, IOLBF, Line_Siz); + -- No error checking??? end Make_Line_Buffered; --------------------- @@ -675,6 +725,7 @@ package body System.File_IO is begin status := setvbuf (File.Stream, Null_Address, IONBF, 0); + -- No error checking??? end Make_Unbuffered; ---------- @@ -684,7 +735,7 @@ package body System.File_IO is function Mode (File : AFCB_Ptr) return File_Mode is begin if File = null then - raise Status_Error; + raise Status_Error with "Mode: file not open"; else return File.Mode; end if; @@ -697,7 +748,7 @@ package body System.File_IO is function Name (File : AFCB_Ptr) return String is begin if File = null then - raise Status_Error; + raise Status_Error with "Name: file not open"; else return File.Name.all (1 .. File.Name'Length - 1); end if; @@ -724,7 +775,7 @@ package body System.File_IO is procedure Tmp_Name (Buffer : Address); pragma Import (C, Tmp_Name, "__gnat_tmp_name"); - -- set buffer (a String address) with a temporary filename + -- Set buffer (a String address) with a temporary filename Stream : FILEs := C_Stream; -- Stream which we open in response to this request @@ -744,9 +795,9 @@ package body System.File_IO is -- Indicates temporary file case Namelen : constant Integer := max_path_len; - -- Length required for file name, not including final ASCII.NUL - -- Note that we used to reference L_tmpnam here, which is not - -- reliable since __gnat_tmp_name does not always use tmpnam. + -- Length required for file name, not including final ASCII.NUL. + -- Note that we used to reference L_tmpnam here, which is not reliable + -- since __gnat_tmp_name does not always use tmpnam. Namestr : aliased String (1 .. Namelen + 1); -- Name as given or temporary file name with ASCII.NUL appended @@ -758,12 +809,12 @@ package body System.File_IO is Full_Name_Len : Integer; -- Length of name actually stored in Fullname - Encoding : System.CRTL.Filename_Encoding; + Encoding : CRTL.Filename_Encoding; -- Filename encoding specified into the form parameter begin if File_Ptr /= null then - raise Status_Error; + raise Status_Error with "file already open"; end if; -- Acquire form string, setting required NUL terminator @@ -797,7 +848,7 @@ package body System.File_IO is Shared := No; else - raise Use_Error; + raise Use_Error with "invalid Form"; end if; end; @@ -810,16 +861,16 @@ package body System.File_IO is Form_Parameter (Formstr, "encoding", V1, V2); if V1 = 0 then - Encoding := System.CRTL.Unspecified; + Encoding := CRTL.Unspecified; elsif Formstr (V1 .. V2) = "utf8" then - Encoding := System.CRTL.UTF8; + Encoding := CRTL.UTF8; elsif Formstr (V1 .. V2) = "8bits" then - Encoding := System.CRTL.ASCII_8bits; + Encoding := CRTL.ASCII_8bits; else - raise Use_Error; + raise Use_Error with "invalid Form"; end if; end; @@ -851,13 +902,13 @@ package body System.File_IO is if Tempfile then if not Creat then - raise Name_Error; + raise Name_Error with "opening temp file without creating it"; end if; Tmp_Name (Namestr'Address); if Namestr (1) = ASCII.NUL then - raise Use_Error; + raise Use_Error with "invalid temp file name"; end if; -- Chain to temp file list, ensuring thread safety with a lock @@ -878,7 +929,7 @@ package body System.File_IO is else if Name'Length > Namelen then - raise Name_Error; + raise Name_Error with "file name too long"; end if; Namestr (1 .. Name'Length) := Name; @@ -890,7 +941,7 @@ package body System.File_IO is full_name (Namestr'Address, Fullname'Address); if Fullname (1) = ASCII.NUL then - raise Use_Error; + raise Use_Error with Errno_Message (Name); end if; Full_Name_Len := 1; @@ -902,7 +953,7 @@ package body System.File_IO is -- Fullname is generated by calling system's full_name. The problem -- is, full_name does nothing about the casing, so a file name - -- comparison may generally speaking not be valid on non-case + -- comparison may generally speaking not be valid on non-case- -- sensitive systems, and in particular we get unexpected failures -- on Windows/Vista because of this. So we use s-casuti to force -- the name to lower case. @@ -911,8 +962,8 @@ package body System.File_IO is To_Lower (Fullname (1 .. Full_Name_Len)); end if; - -- If Shared=None or Shared=Yes, then check for the existence - -- of another file with exactly the same full name. + -- If Shared=None or Shared=Yes, then check for the existence of + -- another file with exactly the same full name. if Shared /= No then declare @@ -937,7 +988,7 @@ package body System.File_IO is if Shared = None or else P.Shared_Status = None then - raise Use_Error; + raise Use_Error with "reopening shared file"; -- If both files have Shared=Yes, then we acquire the -- stream from the located file to use as our stream. @@ -983,7 +1034,7 @@ package body System.File_IO is if not Creat and then Fopstr (1) /= 'r' then if file_exists (Namestr'Address) = 0 then - raise Name_Error; + raise Name_Error with Errno_Message (Name); end if; end if; @@ -1007,10 +1058,8 @@ package body System.File_IO is -- Should we raise Device_Error for ENOSPC??? declare - subtype Cint is Interfaces.C.int; - function Is_File_Not_Found_Error - (Errno_Value : Cint) return Cint; + (Errno_Value : Integer) return Integer; -- Non-zero when the given errno value indicates a non- -- existing file. @@ -1018,13 +1067,13 @@ package body System.File_IO is (C, Is_File_Not_Found_Error, "__gnat_is_file_not_found_error"); + Errno : constant Integer := OS_Lib.Errno; + Message : constant String := Errno_Message (Name, Errno); begin - if - Is_File_Not_Found_Error (Cint (System.OS_Lib.Errno)) /= 0 - then - raise Name_Error; + if Is_File_Not_Found_Error (Errno) /= 0 then + raise Name_Error with Message; else - raise Use_Error; + raise Use_Error with Message; end if; end; end if; @@ -1032,8 +1081,8 @@ package body System.File_IO is end if; -- Stream has been successfully located or opened, so now we are - -- committed to completing the opening of the file. Allocate block - -- on heap and fill in its fields. + -- committed to completing the opening of the file. Allocate block on + -- heap and fill in its fields. File_Ptr := AFCB_Allocate (Dummy_FCB); @@ -1053,6 +1102,23 @@ package body System.File_IO is Append_Set (File_Ptr); end Open; + ------------------------ + -- Raise_Device_Error -- + ------------------------ + + procedure Raise_Device_Error + (File : AFCB_Ptr; Errno : Integer := OS_Lib.Errno) + is + begin + -- Clear error status so that the same error is not reported twice + + if File /= null then + clearerr (File.Stream); + end if; + + raise Device_Error with Errno_Message (Errno); + end Raise_Device_Error; + -------------- -- Read_Buf -- -------------- @@ -1067,13 +1133,13 @@ package body System.File_IO is return; elsif ferror (File.Stream) /= 0 then - raise Device_Error; + Raise_Device_Error (File); elsif Nread = 0 then raise End_Error; else -- 0 < Nread < Siz - raise Data_Error; + raise Data_Error with "not enough data read"; end if; end Read_Buf; @@ -1088,7 +1154,7 @@ package body System.File_IO is Count := fread (Buf, 1, Siz, File.Stream); if Count = 0 and then ferror (File.Stream) /= 0 then - raise Device_Error; + Raise_Device_Error (File); end if; end Read_Buf; @@ -1105,9 +1171,9 @@ package body System.File_IO is Reset (File_Ptr, File.Mode); end Reset; - -- The reset with a change in mode is done using freopen, and is - -- not permitted except for regular files (since otherwise there - -- is no name for the freopen, and in any case it seems meaningless) + -- The reset with a change in mode is done using freopen, and is not + -- permitted except for regular files (since otherwise there is no name for + -- the freopen, and in any case it seems meaningless). procedure Reset (File_Ptr : access AFCB_Ptr; Mode : File_Mode) is File : AFCB_Ptr renames File_Ptr.all; @@ -1120,25 +1186,29 @@ package body System.File_IO is -- file that is not a regular file, or for a system file. Note that we -- allow the "change" of mode if it is not in fact doing a change. - if Mode /= File.Mode - and then (File.Shared_Status = Yes - or else File.Name'Length <= 1 - or else File.Is_System_File - or else not File.Is_Regular_File) - then - raise Use_Error; + if Mode /= File.Mode then + if File.Shared_Status = Yes then + raise Use_Error with "cannot change mode of shared file"; + elsif File.Name'Length <= 1 then + raise Use_Error with "cannot change mode of temp file"; + elsif File.Is_System_File then + raise Use_Error with "cannot change mode of system file"; + elsif not File.Is_Regular_File then + raise Use_Error with "cannot change mode of non-regular file"; + end if; + end if; - -- For In_File or Inout_File for a regular file, we can just do a - -- rewind if the mode is unchanged, which is more efficient than - -- doing a full reopen. + -- For In_File or Inout_File for a regular file, we can just do a rewind + -- if the mode is unchanged, which is more efficient than doing a full + -- reopen. - elsif Mode = File.Mode + if Mode = File.Mode and then Mode <= Inout_File then rewind (File.Stream); - -- Here the change of mode is permitted, we do it by reopening the - -- file in the new mode and replacing the stream with a new stream. + -- Here the change of mode is permitted, we do it by reopening the file + -- in the new mode and replacing the stream with a new stream. else Fopen_Mode @@ -1164,17 +1234,17 @@ package body System.File_IO is procedure Write_Buf (File : AFCB_Ptr; Buf : Address; Siz : size_t) is begin - -- Note: for most purposes, the Siz and 1 parameters in the fwrite - -- call could be reversed, but on VMS, this is a better choice, since - -- for some file formats, reversing the parameters results in records - -- of one byte each. + -- Note: for most purposes, the Siz and 1 parameters in the fwrite call + -- could be reversed, but on VMS, this is a better choice, since for + -- some file formats, reversing the parameters results in records of one + -- byte each. SSL.Abort_Defer.all; if fwrite (Buf, Siz, 1, File.Stream) /= 1 then if Siz /= 0 then SSL.Abort_Undefer.all; - raise Device_Error; + Raise_Device_Error (File); end if; end if; diff --git a/gcc/ada/s-fileio.ads b/gcc/ada/s-fileio.ads index e3a9abe0980..5ee0c5b99d9 100644 --- a/gcc/ada/s-fileio.ads +++ b/gcc/ada/s-fileio.ads @@ -125,8 +125,8 @@ package System.File_IO is -- if used with temporary files or standard files. function Form (File : FCB.AFCB_Ptr) return String; - -- Returns the form as supplied by create, open or reset - -- The string is normalized to all lower case letters. + -- Returns the form as supplied by create, open or reset The string is + -- normalized to all lower case letters. function Is_Open (File : FCB.AFCB_Ptr) return Boolean; -- Determines if file is open or not @@ -145,25 +145,25 @@ package System.File_IO is -- not opened in the normal manner. Note that the caller is responsible -- for task lock out to protect the global data structures if this is -- necessary (it is needed for the calls from within this unit itself, - -- but not required for the calls from Text_IO and Wide_Text_IO that - -- are made during elaboration of the environment task). + -- but not required for the calls from Text_IO and [Wide_]Wide_Text_IO + -- that are made during elaboration of the environment task). procedure Check_File_Open (File : FCB.AFCB_Ptr); - -- If the current file is not open, then Status_Error is raised. - -- Otherwise control returns normally (with File pointing to the - -- control block for the open file. + -- If the current file is not open, then Status_Error is raised. Otherwise + -- control returns normally (with File pointing to the control block for + -- the open file. procedure Check_Read_Status (File : FCB.AFCB_Ptr); - -- If the current file is not open, then Status_Error is raised. If - -- the file is open, then the mode is checked to ensure that reading - -- is permitted, and if not Mode_Error is raised, otherwise control - -- returns normally. + -- If the current file is not open, then Status_Error is raised. If the + -- file is open, then the mode is checked to make sure that reading is + -- permitted, and if not Mode_Error is raised, otherwise control returns + -- normally. procedure Check_Write_Status (File : FCB.AFCB_Ptr); - -- If the current file is not open, then Status_Error is raised. If - -- the file is open, then the mode is checked to ensure that writing - -- is permitted, and if not Mode_Error is raised, otherwise control - -- returns normally. + -- If the current file is not open, then Status_Error is raised. If the + -- file is open, then the mode is checked to ensure that writing is + -- permitted, and if not Mode_Error is raised, otherwise control returns + -- normally. function End_Of_File (File : FCB.AFCB_Ptr) return Boolean; -- File must be opened in read mode. True is returned if the stream is @@ -171,30 +171,28 @@ package System.File_IO is -- The position of the stream is not affected. procedure Flush (File : FCB.AFCB_Ptr); - -- Flushes the stream associated with the given file. The file must be - -- open and in write mode (if not, an appropriate exception is raised) + -- Flushes the stream associated with the given file. The file must be open + -- and in write mode (if not, an appropriate exception is raised) function Form_Boolean (Form : String; Keyword : String; - Default : Boolean) - return Boolean; - -- Searches form string for an entry of the form Keyword=xx where xx is - -- either Yes/No or y/n. Returns True if Yes or Y is found, False if No - -- or N is found. If the keyword parameter is not found, returns the - -- value given as Default. May raise Use_Error if a form string syntax - -- error is detected. Keyword and Form must be in lower case. + Default : Boolean) return Boolean; + -- Searches form string for an entry of the form keyword=xx where xx is + -- either yes/no or y/n. Returns True if yes or y is found, False if no or + -- n is found. If the keyword parameter is not found, returns the value + -- given as Default. May raise Use_Error if a form string syntax error is + -- detected. Keyword and Form must be in lower case. function Form_Integer (Form : String; Keyword : String; - Default : Integer) - return Integer; - -- Searches form string for an entry of the form Keyword=xx where xx is - -- an unsigned decimal integer in the range 0 to 999_999. Returns this - -- integer value if it is found. If the keyword parameter is not found, - -- returns the value given as Default. Raise Use_Error if a form string - -- syntax error is detected. Keyword and Form must be in lower case. + Default : Integer) return Integer; + -- Searches form string for an entry of the form Keyword=xx where xx is an + -- unsigned decimal integer in the range 0 to 999_999. Returns this integer + -- value if it is found. If the keyword parameter is not found, returns the + -- value given as Default. Raise Use_Error if a form string syntax error is + -- detected. Keyword and Form must be in lower case. procedure Form_Parameter (Form : String; @@ -221,22 +219,22 @@ package System.File_IO is Buf : Address; Siz : Interfaces.C_Streams.size_t; Count : out Interfaces.C_Streams.size_t); - -- Reads Siz bytes from File.Stream into Buf. The caller has checked - -- that the file is open in read mode. Device Error is raised if an error + -- Reads Siz bytes from File.Stream into Buf. The caller has checked that + -- the file is open in read mode. Device Error is raised if an error -- occurs. Count is the actual number of bytes read, which may be less -- than Siz if the end of file is encountered. procedure Append_Set (File : FCB.AFCB_Ptr); - -- If the mode of the file is Append_File, then the file is positioned - -- at the end of file using fseek, otherwise this call has no effect. + -- If the mode of the file is Append_File, then the file is positioned at + -- the end of file using fseek, otherwise this call has no effect. procedure Write_Buf (File : FCB.AFCB_Ptr; Buf : Address; Siz : Interfaces.C_Streams.size_t); - -- Writes size_t bytes to File.Stream from Buf. The caller has checked - -- that the file is open in write mode. Raises Device_Error if the - -- complete buffer cannot be written. + -- Writes size_t bytes to File.Stream from Buf. The caller has checked that + -- the file is open in write mode. Raises Device_Error if the complete + -- buffer cannot be written. procedure Make_Unbuffered (File : FCB.AFCB_Ptr); diff --git a/gcc/ada/s-os_lib.adb b/gcc/ada/s-os_lib.adb index 0f2081a0e87..f7341367688 100755 --- a/gcc/ada/s-os_lib.adb +++ b/gcc/ada/s-os_lib.adb @@ -77,8 +77,17 @@ package body System.OS_Lib is ----------------------- function Args_Length (Args : Argument_List) return Natural; - -- Returns total number of characters needed to create a string - -- of all Args terminated by ASCII.NUL characters + -- Returns total number of characters needed to create a string of all Args + -- terminated by ASCII.NUL characters. + + procedure Create_Temp_File_Internal + (FD : out File_Descriptor; + Name : out String_Access; + Stdout : Boolean); + -- Internal routine to implement two Create_Temp_File routines. If Stdout + -- is set to True the created descriptor is stdout-compatible, otherwise + -- it might not be depending on the OS (VMS is one example). The first two + -- parameters are as in Create_Temp_File. function C_String_Length (S : Address) return Integer; -- Returns the length of a C string. Does check for null address @@ -748,11 +757,58 @@ package body System.OS_Lib is procedure Create_Temp_File (FD : out File_Descriptor; Name : out String_Access) + is + begin + Create_Temp_File_Internal (FD, Name, Stdout => False); + end Create_Temp_File; + + procedure Create_Temp_Output_File + (FD : out File_Descriptor; + Name : out String_Access) + is + begin + Create_Temp_File_Internal (FD, Name, Stdout => True); + end Create_Temp_Output_File; + + ------------------------------- + -- Create_Temp_File_Internal -- + ------------------------------- + + procedure Create_Temp_File_Internal + (FD : out File_Descriptor; + Name : out String_Access; + Stdout : Boolean) is Pos : Positive; Attempts : Natural := 0; Current : String (Current_Temp_File_Name'Range); + --------------------------------- + -- Create_New_Output_Text_File -- + --------------------------------- + + function Create_New_Output_Text_File + (Name : String) return File_Descriptor; + -- Similar to Create_Output_Text_File, except it fails if the file + -- already exists. We need this behavior to ensure we don't accidentally + -- open a temp file that has just been created by a concurrently running + -- process. There is no point exposing this function, as it's generally + -- not particularly useful. + + function Create_New_Output_Text_File + (Name : String) return File_Descriptor is + function C_Create_File + (Name : C_File_Name) return File_Descriptor; + pragma Import (C, C_Create_File, "__gnat_create_output_file_new"); + + C_Name : String (1 .. Name'Length + 1); + + begin + C_Name (1 .. Name'Length) := Name; + C_Name (C_Name'Last) := ASCII.NUL; + return C_Create_File (C_Name (C_Name'First)'Address); + end Create_New_Output_Text_File; + begin -- Loop until a new temp file can be created @@ -814,7 +870,11 @@ package body System.OS_Lib is -- Attempt to create the file - FD := Create_New_File (Current, Binary); + if Stdout then + FD := Create_New_Output_Text_File (Current); + else + FD := Create_New_File (Current, Binary); + end if; if FD /= Invalid_FD then Name := new String'(Current); @@ -836,7 +896,7 @@ package body System.OS_Lib is end if; end if; end loop File_Loop; - end Create_Temp_File; + end Create_Temp_File_Internal; ----------------- -- Delete_File -- diff --git a/gcc/ada/s-os_lib.ads b/gcc/ada/s-os_lib.ads index b77b3f01266..341a27953ab 100755 --- a/gcc/ada/s-os_lib.ads +++ b/gcc/ada/s-os_lib.ads @@ -245,9 +245,26 @@ package System.OS_Lib is Name : out String_Access); -- Create and open for writing a temporary file in the current working -- directory. The name of the file and the File Descriptor are returned. - -- No mode parameter is provided. Since this is a temporary file, there is - -- no point in doing text translation on it. It is the responsibility of - -- the caller to deallocate the access value returned in Name. + -- It is the responsibility of the caller to deallocate the access value + -- returned in Name. + -- + -- The file is opened in binary mode (no text translation). + -- + -- This procedure will always succeed if the current working directory is + -- writable. If the current working directory is not writable, then + -- Invalid_FD is returned for the file descriptor and null for the Name. + -- There is no race condition problem between processes trying to create + -- temp files at the same time in the same directory. + + procedure Create_Temp_Output_File + (FD : out File_Descriptor; + Name : out String_Access); + -- Create and open for writing a temporary file in the current working + -- directory suitable to redirect standard output. The name of the file and + -- the File Descriptor are returned. It is the responsibility of the caller + -- to deallocate the access value returned in Name. + -- + -- The file is opened in text mode -- -- This procedure will always succeed if the current working directory is -- writable. If the current working directory is not writable, then diff --git a/gcc/ada/s-osinte-rtems.ads b/gcc/ada/s-osinte-rtems.ads index 5e3d9192014..70e4a27e0a4 100644 --- a/gcc/ada/s-osinte-rtems.ads +++ b/gcc/ada/s-osinte-rtems.ads @@ -625,6 +625,7 @@ private process_shared : int; prio_ceiling : int; protocol : int; + mutex_type : int; recursive : int; end record; pragma Convention (C, pthread_mutexattr_t); diff --git a/gcc/ada/s-stchop-rtems.adb b/gcc/ada/s-stchop-rtems.adb index 615950e7fee..ac0cfd0f489 100644 --- a/gcc/ada/s-stchop-rtems.adb +++ b/gcc/ada/s-stchop-rtems.adb @@ -80,8 +80,9 @@ package body System.Stack_Checking.Operations is is pragma Unreferenced (Stack_Address); - -- RTEMS has a routine to check this. So use it. - function rtems_stack_checker_is_blown return Interfaces.C.int; + -- RTEMS has a routine to check if the stack is blown. + -- It returns a C99 bool. + function rtems_stack_checker_is_blown return Interfaces.C.unsigned_char; pragma Import (C, rtems_stack_checker_is_blown, "rtems_stack_checker_is_blown"); diff --git a/gcc/ada/sem_aggr.adb b/gcc/ada/sem_aggr.adb index af29d9a3fdc..ad01bd18117 100644 --- a/gcc/ada/sem_aggr.adb +++ b/gcc/ada/sem_aggr.adb @@ -509,9 +509,8 @@ package body Sem_Aggr is ------------------------ function Array_Aggr_Subtype - (N : Node_Id; - Typ : Entity_Id) - return Entity_Id + (N : Node_Id; + Typ : Entity_Id) return Entity_Id is Aggr_Dimension : constant Pos := Number_Dimensions (Typ); -- Number of aggregate index dimensions @@ -618,7 +617,7 @@ package body Sem_Aggr is -- Array_Aggr_Subtype variables Itype : Entity_Id; - -- the final itype of the overall aggregate + -- The final itype of the overall aggregate Index_Constraints : constant List_Id := New_List; -- The list of index constraints of the aggregate itype @@ -626,8 +625,8 @@ package body Sem_Aggr is -- Start of processing for Array_Aggr_Subtype begin - -- Make sure that the list of index constraints is properly attached - -- to the tree, and then collect the aggregate bounds. + -- Make sure that the list of index constraints is properly attached to + -- the tree, and then collect the aggregate bounds. Set_Parent (Index_Constraints, N); Collect_Aggr_Bounds (N, 1); @@ -672,13 +671,13 @@ package body Sem_Aggr is Itype := Create_Itype (E_Array_Subtype, N); - Set_First_Rep_Item (Itype, First_Rep_Item (Typ)); - Set_Convention (Itype, Convention (Typ)); - Set_Depends_On_Private (Itype, Has_Private_Component (Typ)); - Set_Etype (Itype, Base_Type (Typ)); - Set_Has_Alignment_Clause (Itype, Has_Alignment_Clause (Typ)); - Set_Is_Aliased (Itype, Is_Aliased (Typ)); - Set_Depends_On_Private (Itype, Depends_On_Private (Typ)); + Set_First_Rep_Item (Itype, First_Rep_Item (Typ)); + Set_Convention (Itype, Convention (Typ)); + Set_Depends_On_Private (Itype, Has_Private_Component (Typ)); + Set_Etype (Itype, Base_Type (Typ)); + Set_Has_Alignment_Clause (Itype, Has_Alignment_Clause (Typ)); + Set_Is_Aliased (Itype, Is_Aliased (Typ)); + Set_Depends_On_Private (Itype, Depends_On_Private (Typ)); Copy_Suppress_Status (Index_Check, Typ, Itype); Copy_Suppress_Status (Length_Check, Typ, Itype); @@ -688,22 +687,23 @@ package body Sem_Aggr is Set_Is_Internal (Itype, True); -- A simple optimization: purely positional aggregates of static - -- components should be passed to gigi unexpanded whenever possible, - -- and regardless of the staticness of the bounds themselves. Subse- - -- quent checks in exp_aggr verify that type is not packed, etc. + -- components should be passed to gigi unexpanded whenever possible, and + -- regardless of the staticness of the bounds themselves. Subsequent + -- checks in exp_aggr verify that type is not packed, etc. Set_Size_Known_At_Compile_Time (Itype, Is_Fully_Positional and then Comes_From_Source (N) and then Size_Known_At_Compile_Time (Component_Type (Typ))); - -- We always need a freeze node for a packed array subtype, so that - -- we can build the Packed_Array_Type corresponding to the subtype. - -- If expansion is disabled, the packed array subtype is not built, - -- and we must not generate a freeze node for the type, or else it - -- will appear incomplete to gigi. + -- We always need a freeze node for a packed array subtype, so that we + -- can build the Packed_Array_Type corresponding to the subtype. If + -- expansion is disabled, the packed array subtype is not built, and we + -- must not generate a freeze node for the type, or else it will appear + -- incomplete to gigi. - if Is_Packed (Itype) and then not In_Spec_Expression + if Is_Packed (Itype) + and then not In_Spec_Expression and then Expander_Active then Freeze_Itype (Itype, N); @@ -728,11 +728,10 @@ package body Sem_Aggr is Component_Elmt : Elmt_Id; begin - -- All the components of List are matched against Component and - -- a count is maintained of possible misspellings. When at the - -- end of the analysis there are one or two (not more!) possible - -- misspellings, these misspellings will be suggested as - -- possible correction. + -- All the components of List are matched against Component and a count + -- is maintained of possible misspellings. When at the end of the + -- the analysis there are one or two (not more!) possible misspellings, + -- these misspellings will be suggested as possible correction. Component_Elmt := First_Elmt (Elements); while Nr_Of_Suggestions <= Max_Suggestions @@ -872,7 +871,7 @@ package body Sem_Aggr is Append_To (Exprs, C_Node); P := P + 1; - -- something special for wide strings ??? + -- Something special for wide strings??? end loop; New_N := Make_Aggregate (Loc, Expressions => Exprs); @@ -904,9 +903,9 @@ package body Sem_Aggr is end if; -- Check for aggregates not allowed in configurable run-time mode. - -- We allow all cases of aggregates that do not come from source, - -- since these are all assumed to be small (e.g. bounds of a string - -- literal). We also allow aggregates of types we know to be small. + -- We allow all cases of aggregates that do not come from source, since + -- these are all assumed to be small (e.g. bounds of a string literal). + -- We also allow aggregates of types we know to be small. if not Support_Aggregates_On_Target and then Comes_From_Source (N) @@ -941,10 +940,10 @@ package body Sem_Aggr is -- First a special test, for the case of a positional aggregate -- of characters which can be replaced by a string literal. - -- Do not perform this transformation if this was a string literal - -- to start with, whose components needed constraint checks, or if - -- the component type is non-static, because it will require those - -- checks and be transformed back into an aggregate. + -- Do not perform this transformation if this was a string literal to + -- start with, whose components needed constraint checks, or if the + -- component type is non-static, because it will require those checks + -- and be transformed back into an aggregate. if Number_Dimensions (Typ) = 1 and then Is_Standard_Character_Type (Component_Type (Typ)) @@ -989,10 +988,10 @@ package body Sem_Aggr is Aggr_Resolved : Boolean; Aggr_Typ : constant Entity_Id := Etype (Typ); - -- This is the unconstrained array type, which is the type - -- against which the aggregate is to be resolved. Typ itself - -- is the array type of the context which may not be the same - -- subtype as the subtype for the final aggregate. + -- This is the unconstrained array type, which is the type against + -- which the aggregate is to be resolved. Typ itself is the array + -- type of the context which may not be the same subtype as the + -- subtype for the final aggregate. begin -- In the following we determine whether an others choice is @@ -1002,11 +1001,11 @@ package body Sem_Aggr is -- choice is not allowed. -- If expansion is disabled (generic context, or semantics-only - -- mode) actual subtypes cannot be constructed, and the type of - -- an object may be its unconstrained nominal type. However, if - -- the context is an assignment, we assume that "others" is - -- allowed, because the target of the assignment will have a - -- constrained subtype when fully compiled. + -- mode) actual subtypes cannot be constructed, and the type of an + -- object may be its unconstrained nominal type. However, if the + -- context is an assignment, we assume that "others" is allowed, + -- because the target of the assignment will have a constrained + -- subtype when fully compiled. -- Note that there is no node for Explicit_Actual_Parameter. -- To test for this context we therefore have to test for node @@ -1014,7 +1013,7 @@ package body Sem_Aggr is -- formal parameter. Consequently we also need to test for -- N_Procedure_Call_Statement or N_Function_Call. - Set_Etype (N, Aggr_Typ); -- may be overridden later on + Set_Etype (N, Aggr_Typ); -- May be overridden later on if Is_Constrained (Typ) and then (Pkind = N_Assignment_Statement or else @@ -1080,10 +1079,10 @@ package body Sem_Aggr is Error_Msg_N ("illegal context for aggregate", N); end if; - -- If we can determine statically that the evaluation of the - -- aggregate raises Constraint_Error, then replace the - -- aggregate with an N_Raise_Constraint_Error node, but set the - -- Etype to the right aggregate subtype. Gigi needs this. + -- If we can determine statically that the evaluation of the aggregate + -- raises Constraint_Error, then replace the aggregate with an + -- N_Raise_Constraint_Error node, but set the Etype to the right + -- aggregate subtype. Gigi needs this. if Raises_Constraint_Error (N) then Aggr_Subtyp := Etype (N); @@ -1115,13 +1114,13 @@ package body Sem_Aggr is Index_Typ : constant Entity_Id := Etype (Index); Index_Typ_Low : constant Node_Id := Type_Low_Bound (Index_Typ); Index_Typ_High : constant Node_Id := Type_High_Bound (Index_Typ); - -- The type of the index corresponding to the array sub-aggregate - -- along with its low and upper bounds + -- The type of the index corresponding to the array sub-aggregate along + -- with its low and upper bounds. Index_Base : constant Entity_Id := Base_Type (Index_Typ); Index_Base_Low : constant Node_Id := Type_Low_Bound (Index_Base); Index_Base_High : constant Node_Id := Type_High_Bound (Index_Base); - -- ditto for the base type + -- Ditto for the base type function Add (Val : Uint; To : Node_Id) return Node_Id; -- Creates a new expression node where Val is added to expression To. @@ -1131,16 +1130,16 @@ package body Sem_Aggr is procedure Check_Bound (BH : Node_Id; AH : in out Node_Id); -- Checks that AH (the upper bound of an array aggregate) is <= BH -- (the upper bound of the index base type). If the check fails a - -- warning is emitted, the Raises_Constraint_Error Flag of N is set, + -- warning is emitted, the Raises_Constraint_Error flag of N is set, -- and AH is replaced with a duplicate of BH. procedure Check_Bounds (L, H : Node_Id; AL, AH : Node_Id); -- Checks that range AL .. AH is compatible with range L .. H. Emits a - -- warning if not and sets the Raises_Constraint_Error Flag in N. + -- warning if not and sets the Raises_Constraint_Error flag in N. procedure Check_Length (L, H : Node_Id; Len : Uint); -- Checks that range L .. H contains at least Len elements. Emits a - -- warning if not and sets the Raises_Constraint_Error Flag in N. + -- warning if not and sets the Raises_Constraint_Error flag in N. function Dynamic_Or_Null_Range (L, H : Node_Id) return Boolean; -- Returns True if range L .. H is dynamic or null @@ -1155,11 +1154,10 @@ package body Sem_Aggr is Single_Elmt : Boolean) return Boolean; -- Resolves aggregate expression Expr. Returns False if resolution -- fails. If Single_Elmt is set to False, the expression Expr may be - -- used to initialize several array aggregate elements (this can - -- happen for discrete choices such as "L .. H => Expr" or the others - -- choice). In this event we do not resolve Expr unless expansion is - -- disabled. To know why, see the DELAYED COMPONENT RESOLUTION - -- note above. + -- used to initialize several array aggregate elements (this can happen + -- for discrete choices such as "L .. H => Expr" or the others choice). + -- In this event we do not resolve Expr unless expansion is disabled. + -- To know why, see the DELAYED COMPONENT RESOLUTION note above. --------- -- Add -- @@ -1642,8 +1640,8 @@ package body Sem_Aggr is -- discrete association Prev_Nb_Discrete_Choices : Nat; - -- Used to keep track of the number of discrete choices - -- in the current association. + -- Used to keep track of the number of discrete choices in the + -- current association. begin -- STEP 2 (A): Check discrete choices validity @@ -1690,9 +1688,8 @@ package body Sem_Aggr is Check_Non_Static_Context (Choice); -- Do not range check a choice. This check is redundant - -- since this test is already performed when we check - -- that the bounds of the array aggregate are within - -- range. + -- since this test is already done when we check that the + -- bounds of the array aggregate are within range. Set_Do_Range_Check (Choice, False); end if; @@ -1754,13 +1751,13 @@ package body Sem_Aggr is end if; -- Ada 2005 (AI-287): In case of default initialized component - -- we delay the resolution to the expansion phase + -- we delay the resolution to the expansion phase. if Box_Present (Assoc) then - -- Ada 2005 (AI-287): In case of default initialization - -- of a component the expander will generate calls to - -- the corresponding initialization subprogram. + -- Ada 2005 (AI-287): In case of default initialization of a + -- component the expander will generate calls to the + -- corresponding initialization subprogram. null; @@ -1773,8 +1770,8 @@ package body Sem_Aggr is -- We differentiate here two cases because the expression may -- not be decorated. For example, the analysis and resolution - -- of the expression associated with the others choice will - -- be done later with the full aggregate. In such case we + -- of the expression associated with the others choice will be + -- done later with the full aggregate. In such case we -- duplicate the expression tree to analyze the copy and -- perform the required check. @@ -1810,7 +1807,7 @@ package body Sem_Aggr is end loop; -- If aggregate contains more than one choice then these must be - -- static. Sort them and check that they are contiguous + -- static. Sort them and check that they are contiguous. if Nb_Discrete_Choices > 1 then Sort_Case_Table (Table); diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb index d4f4f51dc33..e37b216ca45 100644 --- a/gcc/ada/sem_attr.adb +++ b/gcc/ada/sem_attr.adb @@ -667,8 +667,8 @@ package body Sem_Attr is end loop; if Present (Q) then - Set_Has_Per_Object_Constraint ( - Defining_Identifier (Q), True); + Set_Has_Per_Object_Constraint + (Defining_Identifier (Q), True); end if; end; @@ -1991,9 +1991,10 @@ package body Sem_Attr is -- entry wrappers, the attributes Count, Caller and AST_Entry require -- a context check - if Aname = Name_Count - or else Aname = Name_Caller - or else Aname = Name_AST_Entry + if Ada_Version >= Ada_05 + and then (Aname = Name_Count + or else Aname = Name_Caller + or else Aname = Name_AST_Entry) then declare Count : Natural := 0; diff --git a/gcc/ada/sem_case.adb b/gcc/ada/sem_case.adb index 5de995d984b..840214d2c64 100644 --- a/gcc/ada/sem_case.adb +++ b/gcc/ada/sem_case.adb @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1996-2008, Free Software Foundation, Inc. -- +-- Copyright (C) 1996-2009, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -61,17 +61,24 @@ package body Sem_Case is procedure Check_Choices (Choice_Table : in out Sort_Choice_Table_Type; Bounds_Type : Entity_Id; + Subtyp : Entity_Id; Others_Present : Boolean; - Msg_Sloc : Source_Ptr); + Case_Node : Node_Id); -- This is the procedure which verifies that a set of case alternatives -- or record variant choices has no duplicates, and covers the range -- specified by Bounds_Type. Choice_Table contains the discrete choices -- to check. These must start at position 1. + -- -- Furthermore Choice_Table (0) must exist. This element is used by -- the sorting algorithm as a temporary. Others_Present is a flag -- indicating whether or not an Others choice is present. Finally -- Msg_Sloc gives the source location of the construct containing the -- choices in the Choice_Table. + -- + -- Bounds_Type is the type whose range must be covered by the alternatives + -- + -- Subtyp is the subtype of the expression. If its bounds are non-static + -- the alternatives must cover its base type. function Choice_Image (Value : Uint; Ctype : Entity_Id) return Name_Id; -- Given a Pos value of enumeration type Ctype, returns the name @@ -94,11 +101,17 @@ package body Sem_Case is ------------------- procedure Check_Choices - (Choice_Table : in out Sort_Choice_Table_Type; + (Choice_Table : in out Sort_Choice_Table_Type; Bounds_Type : Entity_Id; + Subtyp : Entity_Id; Others_Present : Boolean; - Msg_Sloc : Source_Ptr) + Case_Node : Node_Id) is + procedure Explain_Non_Static_Bound; + -- Called when we find a non-static bound, requiring the base type to + -- be covered. Provides where possible a helpful explanation of why the + -- bounds are non-static, since this is not always obvious. + function Lt_Choice (C1, C2 : Natural) return Boolean; -- Comparison routine for comparing Choice_Table entries. Use the lower -- bound of each Choice as the key. @@ -136,6 +149,8 @@ package body Sem_Case is end Issue_Msg; procedure Issue_Msg (Value1 : Uint; Value2 : Uint) is + Msg_Sloc : constant Source_Ptr := Sloc (Case_Node); + begin -- In some situations, we call this with a null range, and -- obviously we don't want to complain in this case! @@ -191,17 +206,65 @@ package body Sem_Case is Choice_Table (Nat (To)) := Choice_Table (Nat (From)); end Move_Choice; + ------------------------------ + -- Explain_Non_Static_Bound -- + ------------------------------ + + procedure Explain_Non_Static_Bound is + Expr : Node_Id; + + begin + if Nkind (Case_Node) = N_Variant_Part then + Expr := Name (Case_Node); + else + Expr := Expression (Case_Node); + end if; + + if Bounds_Type /= Subtyp then + + -- If the case is a variant part, the expression is given by + -- the discriminant itself, and the bounds are the culprits. + + if Nkind (Case_Node) = N_Variant_Part then + Error_Msg_NE + ("bounds of & are not static," & + " alternatives must cover base type", Expr, Expr); + + -- If this is a case statement, the expression may be + -- non-static or else the subtype may be at fault. + + elsif Is_Entity_Name (Expr) then + Error_Msg_NE + ("bounds of & are not static," & + " alternatives must cover base type", Expr, Expr); + + else + Error_Msg_N ("subtype of expression is not static," & + " alternatives must cover base type!", Expr); + end if; + + -- Otherwise the expression is not static, even if the bounds of the + -- type are, or else there are missing alternatives. If both, the + -- additional information may be redundant but harmless. + + elsif not Is_Entity_Name (Expr) then + Error_Msg_N + ("subtype of expression is not static, " & + "alternatives must cover base type!", Expr); + end if; + end Explain_Non_Static_Bound; + -- Variables local to Check_Choices - Choice : Node_Id; - Bounds_Lo : constant Node_Id := Type_Low_Bound (Bounds_Type); - Bounds_Hi : constant Node_Id := Type_High_Bound (Bounds_Type); + Choice : Node_Id; + Bounds_Lo : constant Node_Id := Type_Low_Bound (Bounds_Type); + Bounds_Hi : constant Node_Id := Type_High_Bound (Bounds_Type); Prev_Choice : Node_Id; - Hi : Uint; - Lo : Uint; - Prev_Hi : Uint; + Hi : Uint; + Lo : Uint; + Prev_Hi : Uint; -- Start of processing for Check_Choices @@ -216,6 +279,7 @@ package body Sem_Case is if not Others_Present then Issue_Msg (Bounds_Lo, Bounds_Hi); end if; + return; end if; @@ -227,6 +291,13 @@ package body Sem_Case is if not Others_Present and then Expr_Value (Bounds_Lo) < Lo then Issue_Msg (Bounds_Lo, Lo - 1); + + -- If values are missing outside of the subtype, add explanation. + -- No additional message if only one value is missing. + + if Expr_Value (Bounds_Lo) < Lo - 1 then + Explain_Non_Static_Bound; + end if; end if; for J in 2 .. Choice_Table'Last loop @@ -254,6 +325,10 @@ package body Sem_Case is if not Others_Present and then Expr_Value (Bounds_Hi) > Hi then Issue_Msg (Hi + 1, Bounds_Hi); + + if Expr_Value (Bounds_Hi) > Hi + 1 then + Explain_Non_Static_Bound; + end if; end if; end Check_Choices; @@ -546,27 +621,27 @@ package body Sem_Case is Sort_Choice_Table : Sort_Choice_Table_Type (0 .. Nb_Choices); Choice_Type : constant Entity_Id := Base_Type (Subtyp); - -- The actual type against which the discrete choices are - -- resolved. Note that this type is always the base type not the - -- subtype of the ruling expression, index or discriminant. + -- The actual type against which the discrete choices are resolved. + -- Note that this type is always the base type not the subtype of the + -- ruling expression, index or discriminant. Bounds_Type : Entity_Id; - -- The type from which are derived the bounds of the values - -- covered by the discrete choices (see 3.8.1 (4)). If a discrete - -- choice specifies a value outside of these bounds we have an error. + -- The type from which are derived the bounds of the values covered + -- by the discrete choices (see 3.8.1 (4)). If a discrete choice + -- specifies a value outside of these bounds we have an error. Bounds_Lo : Uint; Bounds_Hi : Uint; -- The actual bounds of the above type Expected_Type : Entity_Id; - -- The expected type of each choice. Equal to Choice_Type, except - -- if the expression is universal, in which case the choices can - -- be of any integer type. + -- The expected type of each choice. Equal to Choice_Type, except if + -- the expression is universal, in which case the choices can be of + -- any integer type. Alt : Node_Id; -- A case statement alternative or a variant in a record type - -- declaration + -- declaration. Choice : Node_Id; Kind : Node_Kind; @@ -576,9 +651,9 @@ package body Sem_Case is -- Remember others choice if it is present (empty otherwise) procedure Check (Choice : Node_Id; Lo, Hi : Node_Id); - -- Checks the validity of the bounds of a choice. When the bounds - -- are static and no error occurred the bounds are entered into - -- the choices table so that they can be sorted later on. + -- Checks the validity of the bounds of a choice. When the bounds + -- are static and no error occurred the bounds are entered into the + -- choices table so that they can be sorted later on. ----------- -- Check -- @@ -628,10 +703,10 @@ package body Sem_Case is if Lo_Val < Bounds_Lo then - -- If the choice is an entity name, then it is a type, and - -- we want to post the message on the reference to this - -- entity. Otherwise we want to post it on the lower bound - -- of the range. + -- If the choice is an entity name, then it is a type, and we + -- want to post the message on the reference to this entity. + -- Otherwise we want to post it on the lower bound of the + -- range. if Is_Entity_Name (Choice) then Enode := Choice; @@ -654,10 +729,9 @@ package body Sem_Case is if Hi_Val > Bounds_Hi then - -- If the choice is an entity name, then it is a type, and - -- we want to post the message on the reference to this - -- entity. Otherwise we want to post it on the upper bound - -- of the range. + -- If the choice is an entity name, then it is a type, and we + -- want to post the message on the reference to this entity. + -- Otherwise post it on the upper bound of the range. if Is_Entity_Name (Choice) then Enode := Choice; @@ -678,9 +752,9 @@ package body Sem_Case is -- Store bounds in the table - -- Note: we still store the bounds, even if they are out of - -- range, since this may prevent unnecessary cascaded errors - -- for values that are covered by such an excessive range. + -- Note: we still store the bounds, even if they are out of range, + -- since this may prevent unnecessary cascaded errors for values + -- that are covered by such an excessive range. Last_Choice := Last_Choice + 1; Sort_Choice_Table (Last_Choice).Lo := Lo; @@ -695,9 +769,9 @@ package body Sem_Case is Raises_CE := False; Others_Present := False; - -- If Subtyp is not a static subtype Ada 95 requires then we use - -- the bounds of its base type to determine the values covered by - -- the discrete choices. + -- If Subtyp is not a static subtype Ada 95 requires then we use the + -- bounds of its base type to determine the values covered by the + -- discrete choices. if Is_OK_Static_Subtype (Subtyp) then Bounds_Type := Subtyp; @@ -848,8 +922,9 @@ package body Sem_Case is Check_Choices (Sort_Choice_Table (0 .. Last_Choice), Bounds_Type, + Subtyp, Others_Present or else (Choice_Type = Universal_Integer), - Sloc (N)); + N); -- Now copy the sorted discrete choices diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb index 75b24952200..174811bb81a 100644 --- a/gcc/ada/sem_ch12.adb +++ b/gcc/ada/sem_ch12.adb @@ -540,12 +540,9 @@ package body Sem_Ch12 is -- initialized before call to Check_Generic_Child_Unit. procedure Install_Formal_Packages (Par : Entity_Id); - -- If any of the formals of the parent are formal packages with box, - -- their formal parts are visible in the parent and thus in the child - -- unit as well. Analogous to what is done in Check_Generic_Actuals - -- for the unit itself. This procedure is also used in an instance, to - -- make visible the proper entities of the actual for a formal package - -- declared with a box. + -- Install the visible part of any formal of the parent that is a formal + -- package. Note that for the case of a formal package with a box, this + -- includes the formal part of the formal package (12.7(10/2)). procedure Install_Parent (P : Entity_Id; In_Body : Boolean := False); -- When compiling an instance of a child unit the parent (which is @@ -1701,18 +1698,18 @@ package body Sem_Ch12 is Lo := Make_Attribute_Reference (Loc, Attribute_Name => Name_First, - Prefix => New_Reference_To (T, Loc)); + Prefix => New_Reference_To (T, Loc)); Set_Etype (Lo, T); Hi := Make_Attribute_Reference (Loc, Attribute_Name => Name_Last, - Prefix => New_Reference_To (T, Loc)); + Prefix => New_Reference_To (T, Loc)); Set_Etype (Hi, T); Set_Scalar_Range (T, Make_Range (Loc, - Low_Bound => Lo, + Low_Bound => Lo, High_Bound => Hi)); Set_Ekind (Base, E_Enumeration_Type); @@ -5217,11 +5214,10 @@ package body Sem_Ch12 is elsif In_Open_Scopes (Inst_Par) then - -- If the parent is already installed verify that the - -- actuals for its formal packages declared with a box - -- are already installed. This is necessary when the - -- child instance is a child of the parent instance. - -- In this case the parent is placed on the scope stack + -- If the parent is already installed, install the actuals + -- for its formal packages. This is necessary when the + -- child instance is a child of the parent instance: + -- in this case, the parent is placed on the scope stack -- but the formal packages are not made visible. Install_Formal_Packages (Inst_Par); @@ -7191,24 +7187,20 @@ package body Sem_Ch12 is if Renamed_Object (E) = Par then exit; - -- The visibility of a formal of an enclosing generic is - -- already correct. + -- The visibility of a formal of an enclosing generic is already + -- correct. elsif Denotes_Formal_Package (E) then null; - elsif Present (Associated_Formal_Package (E)) - and then Box_Present (Parent (Associated_Formal_Package (E))) - then + elsif Present (Associated_Formal_Package (E)) then Check_Generic_Actuals (Renamed_Object (E), True); Set_Is_Hidden (E, False); -- Find formal package in generic unit that corresponds to -- (instance of) formal package in instance. - while Present (Gen_E) - and then Chars (Gen_E) /= Chars (E) - loop + while Present (Gen_E) and then Chars (Gen_E) /= Chars (E) loop Next_Entity (Gen_E); end loop; @@ -8365,7 +8357,7 @@ package body Sem_Ch12 is "with volatile actual", Actual); end if; - -- formal in-parameter + -- Formal in-parameter else -- The instantiation of a generic formal in-parameter is constant diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb index c514206c00d..7dd9629da6a 100644 --- a/gcc/ada/sem_ch3.adb +++ b/gcc/ada/sem_ch3.adb @@ -784,7 +784,7 @@ package body Sem_Ch3 is Anon_Type := Create_Itype - (E_Anonymous_Access_Type, Related_Nod, Scope_Id => Anon_Scope); + (E_Anonymous_Access_Type, Related_Nod, Scope_Id => Anon_Scope); if All_Present (N) and then Ada_Version >= Ada_05 @@ -825,8 +825,7 @@ package body Sem_Ch3 is Find_Type (Subtype_Mark (N)); Desig_Type := Entity (Subtype_Mark (N)); - Set_Directly_Designated_Type - (Anon_Type, Desig_Type); + Set_Directly_Designated_Type (Anon_Type, Desig_Type); Set_Etype (Anon_Type, Anon_Type); -- Make sure the anonymous access type has size and alignment fields @@ -2883,12 +2882,11 @@ package body Sem_Ch3 is Apply_Length_Check (E, T); end if; - -- If the type is limited unconstrained with defaulted discriminants - -- and there is no expression, then the object is constrained by the + -- If the type is limited unconstrained with defaulted discriminants and + -- there is no expression, then the object is constrained by the -- defaults, so it is worthwhile building the corresponding subtype. - elsif (Is_Limited_Record (T) - or else Is_Concurrent_Type (T)) + elsif (Is_Limited_Record (T) or else Is_Concurrent_Type (T)) and then not Is_Constrained (T) and then Has_Discriminants (T) then diff --git a/gcc/ada/sem_eval.adb b/gcc/ada/sem_eval.adb index 18853d72729..6e06e8353ae 100644 --- a/gcc/ada/sem_eval.adb +++ b/gcc/ada/sem_eval.adb @@ -5018,7 +5018,7 @@ package body Sem_Eval is if Attribute_Name (N) = Name_Size then Error_Msg_N - ("size attribute is only static for scalar type " & + ("size attribute is only static for static scalar type " & "(RM 4.9(7,8))", N); -- Flag array cases diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb index 902cb30e825..4d56d36ee39 100644 --- a/gcc/ada/sem_prag.adb +++ b/gcc/ada/sem_prag.adb @@ -3459,6 +3459,15 @@ package body Sem_Prag is else Set_Imported (Def_Id); + if Is_Subprogram (Def_Id) + and then Is_Abstract_Subprogram (Def_Id) + then + Error_Msg_Sloc := Sloc (Def_Id); + Error_Msg_NE + ("cannot import abstract subprogram& declared#", + Arg2, Def_Id); + end if; + -- Special processing for Convention_Intrinsic if C = Convention_Intrinsic then diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb index c6a5a5ace59..96a295cd218 100644 --- a/gcc/ada/sem_res.adb +++ b/gcc/ada/sem_res.adb @@ -2935,10 +2935,8 @@ package body Sem_Res is -- anomalies: the subtype was first built in the subprogram -- declaration, and the current call may be nested. - if Nkind (Actval) = N_Aggregate - and then Has_Discriminants (Etype (Actval)) - then - Analyze_And_Resolve (Actval, Base_Type (Etype (Actval))); + if Nkind (Actval) = N_Aggregate then + Analyze_And_Resolve (Actval, Etype (F)); else Analyze_And_Resolve (Actval, Etype (Actval)); end if; @@ -5390,6 +5388,7 @@ package body Sem_Res is Eval_Call (N); Check_Elab_Call (N); + Warn_On_Overlapping_Actuals (Nam, N); end Resolve_Call; ------------------------------- @@ -8255,8 +8254,8 @@ package body Sem_Res is ----------------------------- procedure Resolve_Type_Conversion (N : Node_Id; Typ : Entity_Id) is - Conv_OK : constant Boolean := Conversion_OK (N); - Operand : constant Node_Id := Expression (N); + Conv_OK : constant Boolean := Conversion_OK (N); + Operand : constant Node_Id := Expression (N); Operand_Typ : constant Entity_Id := Etype (Operand); Target_Typ : constant Entity_Id := Etype (N); Rop : Node_Id; @@ -8401,9 +8400,25 @@ package body Sem_Res is (Ekind (Entity (Orig_N)) = E_Loop_Parameter and then Covers (Orig_T, Etype (Entity (Orig_N))))) then - Error_Msg_Node_2 := Orig_T; - Error_Msg_NE -- CODEFIX - ("?redundant conversion, & is of type &!", N, Entity (Orig_N)); + -- One more check, do not give warning if the analyzed conversion + -- has an expression with non-static bounds, and the bounds of the + -- target are static. This avoids junk warnings in cases where the + -- conversion is necessary to establish staticness, for example in + -- a case statement. + + if not Is_OK_Static_Subtype (Operand_Typ) + and then Is_OK_Static_Subtype (Target_Typ) + then + null; + + -- Here we give the redundant conversion warning + + else + Error_Msg_Node_2 := Orig_T; + Error_Msg_NE -- CODEFIX + ("?redundant conversion, & is of type &!", + N, Entity (Orig_N)); + end if; end if; end if; diff --git a/gcc/ada/sem_scil.adb b/gcc/ada/sem_scil.adb index f47d1288f81..cd4e66be554 100644 --- a/gcc/ada/sem_scil.adb +++ b/gcc/ada/sem_scil.adb @@ -285,6 +285,14 @@ package body Sem_SCIL is return Found_Node; end if; + -- Actions in handled sequence of statements + + when + N_Handled_Sequence_Of_Statements => + if Find_SCIL_Node (Statements (P)) then + return Found_Node; + end if; + -- Conditions of while expression or elsif. when N_Iteration_Scheme | @@ -505,7 +513,6 @@ package body Sem_SCIL is N_Function_Call | N_Function_Specification | N_Generic_Association | - N_Handled_Sequence_Of_Statements | N_Identifier | N_In | N_Index_Or_Discriminant_Constraint | diff --git a/gcc/ada/sem_type.adb b/gcc/ada/sem_type.adb index 931112c472d..d35326e1a50 100644 --- a/gcc/ada/sem_type.adb +++ b/gcc/ada/sem_type.adb @@ -732,7 +732,7 @@ package body Sem_Type is begin -- If either operand missing, then this is an error, but ignore it (and -- pretend we have a cover) if errors already detected, since this may - -- simply mean we have malformed trees. + -- simply mean we have malformed trees or a semantic error upstream. if No (T1) or else No (T2) then if Total_Errors_Detected /= 0 then @@ -791,7 +791,7 @@ package body Sem_Type is or else Scope (T1) /= Scope (T2)); end if; - -- Literals are compatible with types in a given "class" + -- Literals are compatible with types in a given "class" elsif (T2 = Universal_Integer and then Is_Integer_Type (T1)) or else (T2 = Universal_Real and then Is_Real_Type (T1)) @@ -803,7 +803,8 @@ package body Sem_Type is then return True; - -- The context may be class wide + -- The context may be class wide, and a class-wide type is + -- compatible with any member of the class. elsif Is_Class_Wide_Type (T1) and then Is_Ancestor (Root_Type (T1), T2) @@ -816,8 +817,8 @@ package body Sem_Type is then return True; - -- Ada 2005 (AI-345): A class-wide abstract interface type T1 covers a - -- task_type or protected_type implementing T1 + -- Ada 2005 (AI-345): A class-wide abstract interface type covers a + -- task_type or protected_type that implements the interface. elsif Ada_Version >= Ada_05 and then Is_Class_Wide_Type (T1) @@ -884,7 +885,10 @@ package body Sem_Type is then return True; - -- Some contexts require a class of types rather than a specific type + -- Some contexts require a class of types rather than a specific type. + -- For example, conditions require any boolean type, fixed point + -- attributes require some real type, etc. The built-in types Any_XXX + -- represent these classes. elsif (T1 = Any_Integer and then Is_Integer_Type (T2)) or else (T1 = Any_Boolean and then Is_Boolean_Type (T2)) @@ -963,6 +967,8 @@ package body Sem_Type is then return Covers (Corresponding_Remote_Type (T1), T2); + -- and conversely. + elsif Is_Record_Type (T2) and then (Is_Remote_Call_Interface (T2) or else Is_Remote_Types (T2)) @@ -970,9 +976,30 @@ package body Sem_Type is then return Covers (Corresponding_Remote_Type (T2), T1); + -- Synchronized types are represented at run time by their corresponding + -- record type. During expansion one is replaced with the other, but + -- they are compatible views of the same type. + + elsif Is_Record_Type (T1) + and then Is_Concurrent_Type (T2) + and then Present (Corresponding_Record_Type (T2)) + then + return Covers (T1, Corresponding_Record_Type (T2)); + + elsif Is_Concurrent_Type (T1) + and then Present (Corresponding_Record_Type (T1)) + and then Is_Record_Type (T2) + then + return Covers (Corresponding_Record_Type (T1), T2); + + -- During analysis, an attribute reference 'Access has a special type + -- kind: Access_Attribute_Type, to be replaced eventually with the type + -- imposed by context. + elsif Ekind (T2) = E_Access_Attribute_Type and then (Ekind (BT1) = E_General_Access_Type - or else Ekind (BT1) = E_Access_Type) + or else + Ekind (BT1) = E_Access_Type) and then Covers (Designated_Type (T1), Designated_Type (T2)) then -- If the target type is a RACW type while the source is an access @@ -984,6 +1011,8 @@ package body Sem_Type is return True; + -- Ditto for allocators, which eventually resolve to the context type + elsif Ekind (T2) = E_Allocator_Type and then Is_Access_Type (T1) then @@ -1008,7 +1037,7 @@ package body Sem_Type is -- A packed array type covers its corresponding non-packed type. This is -- not legitimate Ada, but allows the omission of a number of otherwise -- useless unchecked conversions, and since this can only arise in - -- (known correct) expanded code, no harm is done + -- (known correct) expanded code, no harm is done. elsif Is_Array_Type (T2) and then Is_Packed (T2) @@ -1065,7 +1094,7 @@ package body Sem_Type is return True; -- Ada 2005 (AI-50217): Additional branches to make the shadow entity - -- compatible with its real entity. + -- obtained through a limited_with compatible with its real entity. elsif From_With_Type (T1) then @@ -1087,7 +1116,7 @@ package body Sem_Type is -- If units in the context have Limited_With clauses on each other, -- either type might have a limited view. Checks performed elsewhere - -- verify that the context type is the non-limited view. + -- verify that the context type is the nonlimited view. if Is_Incomplete_Type (T2) then return Covers (T1, Get_Full_View (Non_Limited_View (T2))); @@ -1111,7 +1140,7 @@ package body Sem_Type is -- Ada 2005 (AI-423): Coverage of formal anonymous access types -- and actual anonymous access types in the context of generic - -- instantiation. We have the following situation: + -- instantiations. We have the following situation: -- generic -- type Formal is private; @@ -1133,7 +1162,7 @@ package body Sem_Type is then return True; - -- Otherwise it doesn't cover! + -- Otherwise, types are not compatible! else return False; diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb index 37965afb69a..5baf60c8dea 100644 --- a/gcc/ada/sem_util.adb +++ b/gcc/ada/sem_util.adb @@ -2137,6 +2137,181 @@ package body Sem_Util is end Denotes_Discriminant; + ------------------------- + -- Denotes_Same_Object -- + ------------------------- + + function Denotes_Same_Object (A1, A2 : Node_Id) return Boolean is + begin + -- If we have entity names, then must be same entity + + if Is_Entity_Name (A1) then + if Is_Entity_Name (A2) then + return Entity (A1) = Entity (A2); + else + return False; + end if; + + -- No match if not same node kind + + elsif Nkind (A1) /= Nkind (A2) then + return False; + + -- For selected components, must have same prefix and selector + + elsif Nkind (A1) = N_Selected_Component then + return Denotes_Same_Object (Prefix (A1), Prefix (A2)) + and then + Entity (Selector_Name (A1)) = Entity (Selector_Name (A2)); + + -- For explicit dereferences, prefixes must be same + + elsif Nkind (A1) = N_Explicit_Dereference then + return Denotes_Same_Object (Prefix (A1), Prefix (A2)); + + -- For indexed components, prefixes and all subscripts must be the same + + elsif Nkind (A1) = N_Indexed_Component then + if Denotes_Same_Object (Prefix (A1), Prefix (A2)) then + declare + Indx1 : Node_Id; + Indx2 : Node_Id; + + begin + Indx1 := First (Expressions (A1)); + Indx2 := First (Expressions (A2)); + while Present (Indx1) loop + + -- Shouldn't we be checking that values are the same??? + + if not Denotes_Same_Object (Indx1, Indx2) then + return False; + end if; + + Next (Indx1); + Next (Indx2); + end loop; + + return True; + end; + else + return False; + end if; + + -- For slices, prefixes must match and bounds must match + + elsif Nkind (A1) = N_Slice + and then Denotes_Same_Object (Prefix (A1), Prefix (A2)) + then + declare + Lo1, Lo2, Hi1, Hi2 : Node_Id; + + begin + Get_Index_Bounds (Etype (A1), Lo1, Hi1); + Get_Index_Bounds (Etype (A2), Lo2, Hi2); + + -- Check whether bounds are statically identical. There is no + -- attempt to detect partial overlap of slices. + + -- What about an array and a slice of an array??? + + return Denotes_Same_Object (Lo1, Lo2) + and then Denotes_Same_Object (Hi1, Hi2); + end; + + -- Literals will appear as indices. Isn't this where we should check + -- Known_At_Compile_Time at least if we are generating warnings ??? + + elsif Nkind (A1) = N_Integer_Literal then + return Intval (A1) = Intval (A2); + + else + return False; + end if; + end Denotes_Same_Object; + + ------------------------- + -- Denotes_Same_Prefix -- + ------------------------- + + function Denotes_Same_Prefix (A1, A2 : Node_Id) return Boolean is + + begin + if Is_Entity_Name (A1) then + if Nkind_In (A2, N_Selected_Component, N_Indexed_Component) then + return Denotes_Same_Object (A1, Prefix (A2)) + or else Denotes_Same_Prefix (A1, Prefix (A2)); + else + return False; + end if; + + elsif Is_Entity_Name (A2) then + return Denotes_Same_Prefix (A2, A1); + + elsif Nkind_In (A1, N_Selected_Component, N_Indexed_Component, N_Slice) + and then + Nkind_In (A2, N_Selected_Component, N_Indexed_Component, N_Slice) + then + declare + Root1, Root2 : Node_Id; + Depth1, Depth2 : Int := 0; + + begin + Root1 := Prefix (A1); + while not Is_Entity_Name (Root1) loop + if not Nkind_In + (Root1, N_Selected_Component, N_Indexed_Component) + then + return False; + else + Root1 := Prefix (Root1); + end if; + + Depth1 := Depth1 + 1; + end loop; + + Root2 := Prefix (A2); + while not Is_Entity_Name (Root2) loop + if not Nkind_In + (Root2, N_Selected_Component, N_Indexed_Component) + then + return False; + else + Root2 := Prefix (Root2); + end if; + + Depth2 := Depth2 + 1; + end loop; + + -- If both have the same depth and they do not denote the same + -- object, they are disjoint and not warning is needed. + + if Depth1 = Depth2 then + return False; + + elsif Depth1 > Depth2 then + Root1 := Prefix (A1); + for I in 1 .. Depth1 - Depth2 - 1 loop + Root1 := Prefix (Root1); + end loop; + + return Denotes_Same_Object (Root1, A2); + + else + Root2 := Prefix (A2); + for I in 1 .. Depth2 - Depth1 - 1 loop + Root2 := Prefix (Root2); + end loop; + + return Denotes_Same_Object (A1, Root2); + end if; + end; + + else + return False; + end if; + end Denotes_Same_Prefix; + ---------------------- -- Denotes_Variable -- ---------------------- diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads index 0e3dde668e6..623a72b2782 100644 --- a/gcc/ada/sem_util.ads +++ b/gcc/ada/sem_util.ads @@ -251,6 +251,15 @@ package Sem_Util is -- components of protected types, and constraint checks on entry -- families constrained by discriminants. + function Denotes_Same_Object (A1, A2 : Node_Id) return Boolean; + function Denotes_Same_Prefix (A1, A2 : Node_Id) return Boolean; + -- Functions to detect suspicious overlapping between actuals in a call, + -- when one of them is writable. The predicates are those proposed in + -- AI05-0144, to detect dangerous order dependence in complex calls. + -- I would add a parameter Warn which enables more extensive testing of + -- cases as we find appropriate when we are only warning ??? Or perhaps + -- return an indication of (Error, Warn, OK) ??? + function Denotes_Variable (N : Node_Id) return Boolean; -- Returns True if node N denotes a single variable without parentheses diff --git a/gcc/ada/sem_warn.adb b/gcc/ada/sem_warn.adb index 407171f1d7b..abfdf1ff668 100644 --- a/gcc/ada/sem_warn.adb +++ b/gcc/ada/sem_warn.adb @@ -2991,6 +2991,7 @@ package body Sem_Warn is Warn_On_Non_Local_Exception := True; Warn_On_Object_Renames_Function := True; Warn_On_Obsolescent_Feature := True; + Warn_On_Overlap := True; Warn_On_Questionable_Missing_Parens := True; Warn_On_Redundant_Constructs := True; Warn_On_Unchecked_Conversion := True; @@ -3001,6 +3002,12 @@ package body Sem_Warn is when 'g' => Set_GNAT_Mode_Warnings; + when 'i' => + Warn_On_Overlap := True; + + when 'I' => + Warn_On_Overlap := False; + when 'm' => Warn_On_Suspicious_Modulus_Value := True; @@ -3139,6 +3146,7 @@ package body Sem_Warn is Warn_On_No_Value_Assigned := False; Warn_On_Non_Local_Exception := False; Warn_On_Obsolescent_Feature := False; + Warn_On_Overlap := False; Warn_On_All_Unread_Out_Parameters := False; Warn_On_Parameter_Order := False; Warn_On_Questionable_Missing_Parens := False; @@ -3535,6 +3543,136 @@ package body Sem_Warn is or else Warn_On_All_Unread_Out_Parameters; end Warn_On_Modified_As_Out_Parameter; + --------------------------------- + -- Warn_On_Overlapping_Actuals -- + --------------------------------- + + procedure Warn_On_Overlapping_Actuals (Subp : Entity_Id; N : Node_Id) is + Act1, Act2 : Node_Id; + Form1, Form2 : Entity_Id; + + begin + if not Warn_On_Overlap then + return; + end if; + + -- Exclude calls rewritten as enumeration literals + + if not Nkind_In (N, N_Function_Call, N_Procedure_Call_Statement) then + return; + end if; + + -- Exclude calls to library subprograms. Container operations specify + -- safe behavior when source and target coincide. + + if Is_Predefined_File_Name + (Unit_File_Name (Get_Source_Unit (Sloc (Subp)))) + then + return; + end if; + + Form1 := First_Formal (Subp); + Act1 := First_Actual (N); + while Present (Form1) and then Present (Act1) loop + if Ekind (Form1) = E_In_Out_Parameter then + Form2 := First_Formal (Subp); + Act2 := First_Actual (N); + while Present (Form2) and then Present (Act2) loop + if Form1 /= Form2 + and then Ekind (Form2) /= E_Out_Parameter + and then + (Denotes_Same_Object (Act1, Act2) + or else + Denotes_Same_Prefix (Act1, Act2)) + then + -- Exclude generic types and guard against previous errors. + + if Error_Posted (N) + or else No (Etype (Act1)) + or else No (Etype (Act2)) + then + null; + + elsif Is_Generic_Type (Etype (Act1)) + or else + Is_Generic_Type (Etype (Act2)) + then + null; + + -- If the actual is a function call in prefix notation, + -- there is no real overlap. + + elsif Nkind (Act2) = N_Function_Call then + null; + + -- If either type is elementary the aliasing is harmless. + + elsif Is_Elementary_Type (Underlying_Type (Etype (Form1))) + or else + Is_Elementary_Type (Underlying_Type (Etype (Form2))) + then + null; + + else + declare + Act : Node_Id; + Form : Entity_Id; + + begin + -- Find matching actual + + Act := First_Actual (N); + Form := First_Formal (Subp); + while Act /= Act2 loop + Next_Formal (Form); + Next_Actual (Act); + end loop; + + -- If the call was written in prefix notation, and + -- thus its prefix before rewriting was a selected + -- component, count only visible actuals in the call. + + if Is_Entity_Name (First_Actual (N)) + and then Nkind (Original_Node (N)) = Nkind (N) + and then Nkind (Name (Original_Node (N))) = + N_Selected_Component + and then + Is_Entity_Name (Prefix (Name (Original_Node (N)))) + and then + Entity (Prefix (Name (Original_Node (N)))) = + Entity (First_Actual (N)) + then + if Act1 = First_Actual (N) then + Error_Msg_FE + ("`IN OUT` prefix overlaps with actual for&?", + Act1, Form); + else + Error_Msg_FE + ("writable actual overlaps with actual for&?", + Act1, Form); + end if; + + else + Error_Msg_FE + ("writable actual overlaps with actual for&?", + Act1, Form); + end if; + end; + end if; + + return; + end if; + + Next_Formal (Form2); + Next_Actual (Act2); + end loop; + end if; + + Next_Formal (Form1); + Next_Actual (Act1); + end loop; + end Warn_On_Overlapping_Actuals; + ------------------------------ -- Warn_On_Suspicious_Index -- ------------------------------ diff --git a/gcc/ada/sem_warn.ads b/gcc/ada/sem_warn.ads index 4ab97be7d67..365ad397d1b 100644 --- a/gcc/ada/sem_warn.ads +++ b/gcc/ada/sem_warn.ads @@ -210,6 +210,11 @@ package Sem_Warn is -- as an out parameter. True if either Warn_On_Modified_Unread is set for -- an only OUT parameter, or if Warn_On_All_Unread_Out_Parameters is set. + procedure Warn_On_Overlapping_Actuals (Subp : Entity_Id; N : Node_Id); + -- Called on a subprogram call. Checks whether an IN OUT actual that is + -- not by-copy may overlap with another actual, thus leading to aliasing + -- in the body of the called subprogram. + procedure Warn_On_Suspicious_Index (Name : Entity_Id; X : Node_Id); -- This is called after resolving an indexed component or a slice. Name -- is the entity for the name of the indexed array, and X is the subscript diff --git a/gcc/ada/styleg.adb b/gcc/ada/styleg.adb index 8bd9f2ee2bd..bf72722cc88 100644 --- a/gcc/ada/styleg.adb +++ b/gcc/ada/styleg.adb @@ -813,12 +813,17 @@ package body Styleg is -- Check_Right_Paren -- ----------------------- - -- In check tokens mode (-gnatyt), right paren must never be preceded by + -- In check tokens mode (-gnatyt), right paren must not be immediately + -- followed by an identifier character, and must never be preceded by -- a space unless it is the initial non-blank character on the line. procedure Check_Right_Paren is begin if Style_Check_Tokens then + if Identifier_Char (Source (Token_Ptr + 1)) then + Error_Space_Required (Token_Ptr + 1); + end if; + Check_No_Space_Before; end if; end Check_Right_Paren; diff --git a/gcc/ada/switch-m.adb b/gcc/ada/switch-m.adb index 316b77e702b..a7a8d192626 100644 --- a/gcc/ada/switch-m.adb +++ b/gcc/ada/switch-m.adb @@ -656,6 +656,7 @@ package body Switch.M is else Follow_Links_For_Files := True; + Follow_Links_For_Dirs := True; end if; -- Processing for eS switch diff --git a/gcc/ada/tbuild.adb b/gcc/ada/tbuild.adb index 7273fde6703..3da3c611198 100644 --- a/gcc/ada/tbuild.adb +++ b/gcc/ada/tbuild.adb @@ -33,7 +33,6 @@ with Opt; use Opt; with Restrict; use Restrict; with Rident; use Rident; with Sem_Aux; use Sem_Aux; -with Sinfo; use Sinfo; with Snames; use Snames; with Stand; use Stand; with Stringt; use Stringt; @@ -626,6 +625,58 @@ package body Tbuild is return Occurrence; end New_Occurrence_Of; + ----------------- + -- New_Op_Node -- + ----------------- + + function New_Op_Node + (New_Node_Kind : Node_Kind; + New_Sloc : Source_Ptr) return Node_Id + is + type Name_Of_Type is array (N_Op) of Name_Id; + Name_Of : constant Name_Of_Type := Name_Of_Type'( + N_Op_And => Name_Op_And, + N_Op_Or => Name_Op_Or, + N_Op_Xor => Name_Op_Xor, + N_Op_Eq => Name_Op_Eq, + N_Op_Ne => Name_Op_Ne, + N_Op_Lt => Name_Op_Lt, + N_Op_Le => Name_Op_Le, + N_Op_Gt => Name_Op_Gt, + N_Op_Ge => Name_Op_Ge, + N_Op_Add => Name_Op_Add, + N_Op_Subtract => Name_Op_Subtract, + N_Op_Concat => Name_Op_Concat, + N_Op_Multiply => Name_Op_Multiply, + N_Op_Divide => Name_Op_Divide, + N_Op_Mod => Name_Op_Mod, + N_Op_Rem => Name_Op_Rem, + N_Op_Expon => Name_Op_Expon, + N_Op_Plus => Name_Op_Add, + N_Op_Minus => Name_Op_Subtract, + N_Op_Abs => Name_Op_Abs, + N_Op_Not => Name_Op_Not, + + -- We don't really need these shift operators, since they never + -- appear as operators in the source, but the path of least + -- resistance is to put them in (the aggregate must be complete) + + N_Op_Rotate_Left => Name_Rotate_Left, + N_Op_Rotate_Right => Name_Rotate_Right, + N_Op_Shift_Left => Name_Shift_Left, + N_Op_Shift_Right => Name_Shift_Right, + N_Op_Shift_Right_Arithmetic => Name_Shift_Right_Arithmetic); + + Nod : constant Node_Id := New_Node (New_Node_Kind, New_Sloc); + + begin + if New_Node_Kind in Name_Of'Range then + Set_Chars (Nod, Name_Of (New_Node_Kind)); + end if; + + return Nod; + end New_Op_Node; + ---------------------- -- New_Reference_To -- ---------------------- diff --git a/gcc/ada/tbuild.ads b/gcc/ada/tbuild.ads index 261776df78f..0b73a53d220 100644 --- a/gcc/ada/tbuild.ads +++ b/gcc/ada/tbuild.ads @@ -27,6 +27,7 @@ -- building specific types of tree nodes. with Namet; use Namet; +with Sinfo; use Sinfo; with Types; use Types; package Tbuild is @@ -196,6 +197,12 @@ package Tbuild is -- "raise Constraint_Error" and returns the root of this tree, -- the N_Raise_Statement node. + function New_Op_Node + (New_Node_Kind : Node_Kind; + New_Sloc : Source_Ptr) return Node_Id; + -- Create node using New_Node and, if its kind is in N_Op, set its Chars + -- field accordingly. + function New_External_Name (Related_Id : Name_Id; Suffix : Character := ' '; diff --git a/gcc/ada/types.ads b/gcc/ada/types.ads index 7340f64129e..cc3603aafa0 100644 --- a/gcc/ada/types.ads +++ b/gcc/ada/types.ads @@ -31,7 +31,7 @@ -- This package contains host independent type definitions which are used -- in more than one unit in the compiler. They are gathered here for easy --- reference, though in some cases the full description is found in the +-- reference, although in some cases the full description is found in the -- relevant module which implements the definition. The main reason that they -- are not in their "natural" specs is that this would cause a lot of inter- -- spec dependencies, and in particular some awkward circular dependencies diff --git a/gcc/ada/usage.adb b/gcc/ada/usage.adb index 6d704403da9..541496c5df8 100644 --- a/gcc/ada/usage.adb +++ b/gcc/ada/usage.adb @@ -424,6 +424,8 @@ begin Write_Line (" H* turn off warnings for hiding variable"); Write_Line (" i* turn on warnings for implementation unit"); Write_Line (" I turn off warnings for implementation unit"); + Write_Line (" .i turn on warnings for overlapping actuals"); + Write_Line (" .I* turn off warnings for overlapping actuals"); Write_Line (" j turn on warnings for obsolescent " & "(annex J) feature"); Write_Line (" J* turn off warnings for obsolescent " & diff --git a/gcc/ada/xsnamest.adb b/gcc/ada/xsnamest.adb index c4c386bd6c8..7dd3ca29883 100644 --- a/gcc/ada/xsnamest.adb +++ b/gcc/ada/xsnamest.adb @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1992-2008, Free Software Foundation, Inc. -- +-- Copyright (C) 1992-2009, Free Software Foundation, Inc. -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -24,10 +24,10 @@ ------------------------------------------------------------------------------ -- This utility is used to make a new version of the Snames package when new --- names are added. This version reads a template file from snames.adt in --- which the numbers are all written as $, and generates a new version of --- the spec file snames.ads (written to snames.ns). It also reads snames.adb --- and generates an updated body (written to snames.nb), and snames.h and +-- names are added. This version reads a template file from snames.ads-tmpl in +-- which the numbers are all written as $, and generates a new version of the +-- spec file snames.ads (written to snames.ns). It also reads snames.adb-tmpl +-- and generates an updated body (written to snames.nb), and snames.h-tmpl and -- generates an updated C header file (written to snames.nh). with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; diff --git a/gcc/alias.c b/gcc/alias.c index 694498ab55a..cdfa6d2d3ac 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -640,7 +640,7 @@ get_alias_set (tree t) aren't types. */ if (! TYPE_P (t)) { - tree inner = t; + tree inner; /* Remove any nops, then give the language a chance to do something with this tree before we look at it. */ @@ -649,8 +649,13 @@ get_alias_set (tree t) if (set != -1) return set; + /* Retrieve the original memory reference if needed. */ + if (TREE_CODE (t) == TARGET_MEM_REF) + t = TMR_ORIGINAL (t); + /* First see if the actual object referenced is an INDIRECT_REF from a restrict-qualified pointer or a "void *". */ + inner = t; while (handled_component_p (inner)) { inner = TREE_OPERAND (inner, 0); @@ -691,7 +696,14 @@ get_alias_set (tree t) requires structural comparisons to identify compatible types use alias set zero. */ if (TYPE_STRUCTURAL_EQUALITY_P (t)) - return 0; + { + /* Allow the language to specify another alias set for this + type. */ + set = lang_hooks.get_alias_set (t); + if (set != -1) + return set; + return 0; + } t = TYPE_CANONICAL (t); /* Canonical types shouldn't form a tree nor should the canonical type require structural equality checks. */ @@ -1053,6 +1065,11 @@ find_base_value (rtx src) return 0; case TRUNCATE: + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + break; if (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (Pmode)) break; /* Fall through. */ @@ -1067,6 +1084,12 @@ find_base_value (rtx src) case ZERO_EXTEND: case SIGN_EXTEND: /* used for NT/Alpha pointers */ + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + break; + { rtx temp = find_base_value (XEXP (src, 0)); @@ -1459,6 +1482,11 @@ find_base_term (rtx x) return REG_BASE_VALUE (x); case TRUNCATE: + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + return 0; if (GET_MODE_SIZE (GET_MODE (x)) < GET_MODE_SIZE (Pmode)) return 0; /* Fall through. */ @@ -1473,6 +1501,12 @@ find_base_term (rtx x) case ZERO_EXTEND: case SIGN_EXTEND: /* Used for Alpha/NT pointers */ + /* As we do not know which address space the pointer is refering to, we can + handle this only if the target does not support different pointer or + address modes depending on the address space. */ + if (!target_default_pointer_address_modes_p ()) + return 0; + { rtx temp = find_base_term (XEXP (x, 0)); @@ -2171,6 +2205,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y) if (! DECL_P (exprx) || ! DECL_P (expry)) return 0; + /* With invalid code we can end up storing into the constant pool. + Bail out to avoid ICEing when creating RTL for this. + See gfortran.dg/lto/20091028-2_0.f90. */ + if (TREE_CODE (exprx) == CONST_DECL + || TREE_CODE (expry) == CONST_DECL) + return 1; + rtlx = DECL_RTL (exprx); rtly = DECL_RTL (expry); @@ -2181,6 +2222,13 @@ nonoverlapping_memrefs_p (const_rtx x, const_rtx y) && ! rtx_equal_p (rtlx, rtly)) return 1; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_P (rtlx) && MEM_P (rtly) + && MEM_ADDR_SPACE (rtlx) != MEM_ADDR_SPACE (rtly)) + return 0; + /* Get the base and offsets of both decls. If either is a register, we know both are and are the same, so use that as the base. The only we can avoid overlap is if we can deduce that they are nonoverlapping @@ -2272,6 +2320,12 @@ true_dependence (const_rtx mem, enum machine_mode mem_mode, const_rtx x, if (nonoverlapping_memrefs_p (mem, x)) return 0; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; + if (mem_mode == VOIDmode) mem_mode = GET_MODE (mem); @@ -2349,6 +2403,12 @@ canon_true_dependence (const_rtx mem, enum machine_mode mem_mode, rtx mem_addr, if (nonoverlapping_memrefs_p (x, mem)) return 0; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; + if (! x_addr) x_addr = get_addr (XEXP (x, 0)); @@ -2409,6 +2469,12 @@ write_dependence_p (const_rtx mem, const_rtx x, int writep) if (nonoverlapping_memrefs_p (x, mem)) return 0; + /* If we have MEMs refering to different address spaces (which can + potentially overlap), we cannot easily tell from the addresses + whether the references overlap. */ + if (MEM_ADDR_SPACE (mem) != MEM_ADDR_SPACE (x)) + return 1; + x_addr = get_addr (XEXP (x, 0)); mem_addr = get_addr (XEXP (mem, 0)); diff --git a/gcc/alloc-pool.c b/gcc/alloc-pool.c index c9d990464ad..cb5d83d23ee 100644 --- a/gcc/alloc-pool.c +++ b/gcc/alloc-pool.c @@ -41,10 +41,10 @@ typedef struct allocation_object_def /* Because we want any type of data to be well aligned after the ID, the following elements are here. They are never accessed so - the allocated object may be even smaller than this structure. */ + the allocated object may be even smaller than this structure. + We do not care about alignment for floating-point types. */ char *align_p; HOST_WIDEST_INT align_i; - long double align_ld; } u; } allocation_object; diff --git a/gcc/auto-inc-dec.c b/gcc/auto-inc-dec.c index 929a2dcade8..3b3006c985f 100644 --- a/gcc/auto-inc-dec.c +++ b/gcc/auto-inc-dec.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "df.h" #include "dbgcnt.h" +#include "target.h" /* This pass was originally removed from flow.c. However there is almost nothing that remains of that code. @@ -613,6 +614,7 @@ try_merge (void) /* The width of the mem being accessed. */ int size = GET_MODE_SIZE (GET_MODE (mem)); rtx last_insn = NULL; + enum machine_mode reg_mode = GET_MODE (inc_reg); switch (inc_insn.form) { @@ -667,33 +669,33 @@ try_merge (void) case SIMPLE_PRE_INC: /* ++size */ if (dump_file) fprintf (dump_file, "trying SIMPLE_PRE_INC\n"); - return attempt_change (gen_rtx_PRE_INC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_PRE_INC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_POST_INC: /* size++ */ if (dump_file) fprintf (dump_file, "trying SIMPLE_POST_INC\n"); - return attempt_change (gen_rtx_POST_INC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_POST_INC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_PRE_DEC: /* --size */ if (dump_file) fprintf (dump_file, "trying SIMPLE_PRE_DEC\n"); - return attempt_change (gen_rtx_PRE_DEC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_PRE_DEC (reg_mode, inc_reg), inc_reg); break; case SIMPLE_POST_DEC: /* size-- */ if (dump_file) fprintf (dump_file, "trying SIMPLE_POST_DEC\n"); - return attempt_change (gen_rtx_POST_DEC (Pmode, inc_reg), inc_reg); + return attempt_change (gen_rtx_POST_DEC (reg_mode, inc_reg), inc_reg); break; case DISP_PRE: /* ++con */ if (dump_file) fprintf (dump_file, "trying DISP_PRE\n"); - return attempt_change (gen_rtx_PRE_MODIFY (Pmode, + return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -702,9 +704,9 @@ try_merge (void) case DISP_POST: /* con++ */ if (dump_file) fprintf (dump_file, "trying POST_DISP\n"); - return attempt_change (gen_rtx_POST_MODIFY (Pmode, + return attempt_change (gen_rtx_POST_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -713,9 +715,9 @@ try_merge (void) case REG_PRE: /* ++reg */ if (dump_file) fprintf (dump_file, "trying PRE_REG\n"); - return attempt_change (gen_rtx_PRE_MODIFY (Pmode, + return attempt_change (gen_rtx_PRE_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -724,9 +726,9 @@ try_merge (void) case REG_POST: /* reg++ */ if (dump_file) fprintf (dump_file, "trying POST_REG\n"); - return attempt_change (gen_rtx_POST_MODIFY (Pmode, + return attempt_change (gen_rtx_POST_MODIFY (reg_mode, inc_reg, - gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (reg_mode, inc_reg, inc_insn.reg1)), inc_reg); @@ -1089,7 +1091,9 @@ find_inc (bool first_try) we are going to increment the result of the add insn. For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ - if (GET_MODE (inc_insn.reg_res) != Pmode) + addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); + if (GET_MODE (inc_insn.reg_res) + != targetm.addr_space.address_mode (as)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); @@ -1138,7 +1142,9 @@ find_inc (bool first_try) { /* For this trick to be correct, the result reg of the inc must be a valid addressing reg. */ - if (GET_MODE (inc_insn.reg_res) != Pmode) + addr_space_t as = MEM_ADDR_SPACE (*mem_insn.mem_loc); + if (GET_MODE (inc_insn.reg_res) + != targetm.addr_space.address_mode (as)) { if (dump_file) fprintf (dump_file, "base reg mode failure.\n"); diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c index 35b4f1724e4..47828bf28c1 100644 --- a/gcc/bb-reorder.c +++ b/gcc/bb-reorder.c @@ -86,10 +86,6 @@ #include "tree-pass.h" #include "df.h" -#ifndef HAVE_conditional_execution -#define HAVE_conditional_execution 0 -#endif - /* The number of rounds. In most cases there will only be 4 rounds, but when partitioning hot and cold basic blocks into separate sections of the .o file there will be an extra round.*/ @@ -2297,5 +2293,3 @@ struct rtl_opt_pass pass_partition_blocks = TODO_dump_func | TODO_verify_rtl_sharing/* todo_flags_finish */ } }; - - diff --git a/gcc/builtins.c b/gcc/builtins.c index 64840e1f620..0cb2bd7fb4e 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -230,6 +230,8 @@ static tree do_mpfr_bessel_n (tree, tree, tree, static tree do_mpfr_remquo (tree, tree, tree); static tree do_mpfr_lgamma_r (tree, tree, tree); +/* Return true if NAME starts with __builtin_ or __sync_. */ + bool is_builtin_name (const char *name) { @@ -240,6 +242,16 @@ is_builtin_name (const char *name) return false; } + +/* Return true if DECL is a function symbol representing a built-in. */ + +bool +is_builtin_fn (tree decl) +{ + return TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl); +} + + /* Return true if NODE should be considered for inline expansion regardless of the optimization level. This means whenever a function is invoked with its "internal" name, which normally contains the prefix "__builtin". */ @@ -5644,7 +5656,8 @@ get_builtin_sync_mem (tree loc, enum machine_mode mode) { rtx addr, mem; - addr = expand_expr (loc, NULL_RTX, Pmode, EXPAND_SUM); + addr = expand_expr (loc, NULL_RTX, ptr_mode, EXPAND_SUM); + addr = convert_memory_address (Pmode, addr); /* Note that we explicitly do not want any alias information for this memory, so that we kill all other live memories. Otherwise we don't @@ -7182,7 +7195,7 @@ fold_builtin_cabs (location_t loc, tree arg, tree type, tree fndecl) { tree res; - if (TREE_CODE (TREE_TYPE (arg)) != COMPLEX_TYPE + if (!validate_arg (arg, COMPLEX_TYPE) || TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) != REAL_TYPE) return NULL_TREE; @@ -7571,7 +7584,7 @@ fold_builtin_cexp (location_t loc, tree arg0, tree type) #endif if (!validate_arg (arg0, COMPLEX_TYPE) - && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + || TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) != REAL_TYPE) return NULL_TREE; #ifdef HAVE_mpc @@ -9226,9 +9239,9 @@ fold_builtin_isascii (location_t loc, tree arg) else { /* Transform isascii(c) -> ((c & ~0x7f) == 0). */ - arg = build2 (BIT_AND_EXPR, integer_type_node, arg, - build_int_cst (NULL_TREE, - ~ (unsigned HOST_WIDE_INT) 0x7f)); + arg = fold_build2 (BIT_AND_EXPR, integer_type_node, arg, + build_int_cst (NULL_TREE, + ~ (unsigned HOST_WIDE_INT) 0x7f)); return fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg, integer_zero_node); } @@ -9266,8 +9279,8 @@ fold_builtin_isdigit (location_t loc, tree arg) return NULL_TREE; arg = fold_convert_loc (loc, unsigned_type_node, arg); - arg = build2 (MINUS_EXPR, unsigned_type_node, arg, - build_int_cst (unsigned_type_node, target_digit0)); + arg = fold_build2 (MINUS_EXPR, unsigned_type_node, arg, + build_int_cst (unsigned_type_node, target_digit0)); return fold_build2_loc (loc, LE_EXPR, integer_type_node, arg, build_int_cst (unsigned_type_node, 9)); } @@ -10005,7 +10018,8 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) break; CASE_FLT_FN (BUILT_IN_CIMAG): - if (validate_arg (arg0, COMPLEX_TYPE)) + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) return non_lvalue_loc (loc, fold_build1_loc (loc, IMAGPART_EXPR, type, arg0)); break; @@ -10051,7 +10065,45 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool ignore) && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) return do_mpc_arg1 (arg0, type, mpc_sqrt); break; -#endif + +#ifdef HAVE_mpc_arc + CASE_FLT_FN (BUILT_IN_CASIN): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_asin); + break; + + CASE_FLT_FN (BUILT_IN_CACOS): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_acos); + break; + + CASE_FLT_FN (BUILT_IN_CATAN): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_atan); + break; + + CASE_FLT_FN (BUILT_IN_CASINH): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_asinh); + break; + + CASE_FLT_FN (BUILT_IN_CACOSH): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_acosh); + break; + + CASE_FLT_FN (BUILT_IN_CATANH): + if (validate_arg (arg0, COMPLEX_TYPE) + && TREE_CODE (TREE_TYPE (TREE_TYPE (arg0))) == REAL_TYPE) + return do_mpc_arg1 (arg0, type, mpc_atanh); + break; +#endif /* HAVE_mpc_arc */ +#endif /* HAVE_mpc */ CASE_FLT_FN (BUILT_IN_CABS): return fold_builtin_cabs (loc, arg0, type, fndecl); @@ -13856,3 +13908,41 @@ fold_call_stmt (gimple stmt, bool ignore) } return NULL_TREE; } + +/* Look up the function in built_in_decls that corresponds to DECL + and set ASMSPEC as its user assembler name. DECL must be a + function decl that declares a builtin. */ + +void +set_builtin_user_assembler_name (tree decl, const char *asmspec) +{ + tree builtin; + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL + && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL + && asmspec != 0); + + builtin = built_in_decls [DECL_FUNCTION_CODE (decl)]; + set_user_assembler_name (builtin, asmspec); + switch (DECL_FUNCTION_CODE (decl)) + { + case BUILT_IN_MEMCPY: + init_block_move_fn (asmspec); + memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec); + break; + case BUILT_IN_MEMSET: + init_block_clear_fn (asmspec); + memset_libfunc = set_user_assembler_libfunc ("memset", asmspec); + break; + case BUILT_IN_MEMMOVE: + memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec); + break; + case BUILT_IN_MEMCMP: + memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec); + break; + case BUILT_IN_ABORT: + abort_libfunc = set_user_assembler_libfunc ("abort", asmspec); + break; + default: + break; + } +} diff --git a/gcc/c-common.c b/gcc/c-common.c index 4de92d0de95..20b24f0c3c2 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -710,6 +710,11 @@ const struct c_common_resword c_common_reswords[] = { "inout", RID_INOUT, D_OBJC }, { "oneway", RID_ONEWAY, D_OBJC }, { "out", RID_OUT, D_OBJC }, + +#ifdef TARGET_ADDR_SPACE_KEYWORDS + /* Any address space keywords recognized by the target. */ + TARGET_ADDR_SPACE_KEYWORDS, +#endif }; const unsigned int num_c_common_reswords = @@ -840,6 +845,19 @@ const struct attribute_spec c_common_format_attribute_table[] = { NULL, 0, 0, false, false, false, NULL } }; +/* Return identifier for address space AS. */ +const char * +c_addr_space_name (addr_space_t as) +{ + unsigned int i; + + for (i = 0; i < num_c_common_reswords; i++) + if (c_common_reswords[i].rid == RID_FIRST_ADDR_SPACE + as) + return c_common_reswords[i].word; + + gcc_unreachable (); +} + /* Push current bindings for the function name VAR_DECLS. */ void @@ -1219,6 +1237,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, op2 = TREE_OPERAND (expr, 2); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself); + STRIP_TYPE_NOPS (op0); if (op0 != orig_op0) ret = build3 (COMPONENT_REF, TREE_TYPE (expr), op0, op1, op2); if (ret != expr) @@ -1235,8 +1254,10 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, op3 = TREE_OPERAND (expr, 3); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself); + STRIP_TYPE_NOPS (op0); op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, maybe_const_itself); + STRIP_TYPE_NOPS (op1); op1 = decl_constant_value_for_optimization (op1); if (op0 != orig_op0 || op1 != orig_op1) ret = build4 (ARRAY_REF, TREE_TYPE (expr), op0, op1, op2, op3); @@ -1293,6 +1314,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, orig_op1 = op1 = TREE_OPERAND (expr, 1); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself); + STRIP_TYPE_NOPS (op0); if (code != MODIFY_EXPR && code != PREDECREMENT_EXPR && code != PREINCREMENT_EXPR @@ -1304,6 +1326,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, if (code != MODIFY_EXPR) op1 = c_fully_fold_internal (op1, in_init, maybe_const_operands, maybe_const_itself); + STRIP_TYPE_NOPS (op1); op1 = decl_constant_value_for_optimization (op1); if (op0 != orig_op0 || op1 != orig_op1 || in_init) ret = in_init @@ -1333,6 +1356,7 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, orig_op0 = op0 = TREE_OPERAND (expr, 0); op0 = c_fully_fold_internal (op0, in_init, maybe_const_operands, maybe_const_itself); + STRIP_TYPE_NOPS (op0); if (code != ADDR_EXPR && code != REALPART_EXPR && code != IMAGPART_EXPR) op0 = decl_constant_value_for_optimization (op0); if (op0 != orig_op0 || in_init) @@ -1372,12 +1396,14 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, orig_op0 = op0 = TREE_OPERAND (expr, 0); orig_op1 = op1 = TREE_OPERAND (expr, 1); op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self); + STRIP_TYPE_NOPS (op0); unused_p = (op0 == (code == TRUTH_ANDIF_EXPR ? truthvalue_false_node : truthvalue_true_node)); c_inhibit_evaluation_warnings += unused_p; op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); + STRIP_TYPE_NOPS (op1); c_inhibit_evaluation_warnings -= unused_p; if (op0 != orig_op0 || op1 != orig_op1 || in_init) @@ -1409,12 +1435,15 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands, orig_op2 = op2 = TREE_OPERAND (expr, 2); op0 = c_fully_fold_internal (op0, in_init, &op0_const, &op0_const_self); + STRIP_TYPE_NOPS (op0); c_inhibit_evaluation_warnings += (op0 == truthvalue_false_node); op1 = c_fully_fold_internal (op1, in_init, &op1_const, &op1_const_self); + STRIP_TYPE_NOPS (op1); c_inhibit_evaluation_warnings -= (op0 == truthvalue_false_node); c_inhibit_evaluation_warnings += (op0 == truthvalue_true_node); op2 = c_fully_fold_internal (op2, in_init, &op2_const, &op2_const_self); + STRIP_TYPE_NOPS (op2); c_inhibit_evaluation_warnings -= (op0 == truthvalue_true_node); if (op0 != orig_op0 || op1 != orig_op1 || op2 != orig_op2) @@ -3790,6 +3819,31 @@ pointer_int_sum (location_t loc, enum tree_code resultcode, return ret; } +/* Wrap a C_MAYBE_CONST_EXPR around an expression that is fully folded + and if NON_CONST is known not to be permitted in an evaluated part + of a constant expression. */ + +tree +c_wrap_maybe_const (tree expr, bool non_const) +{ + bool nowarning = TREE_NO_WARNING (expr); + location_t loc = EXPR_LOCATION (expr); + + /* This should never be called for C++. */ + if (c_dialect_cxx ()) + gcc_unreachable (); + + /* The result of folding may have a NOP_EXPR to set TREE_NO_WARNING. */ + STRIP_TYPE_NOPS (expr); + expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr); + C_MAYBE_CONST_EXPR_NON_CONST (expr) = non_const; + if (nowarning) + TREE_NO_WARNING (expr) = 1; + protected_set_expr_location (expr, loc); + + return expr; +} + /* Wrap a SAVE_EXPR around EXPR, if appropriate. Like save_expr, but for C folds the inside expression and wraps a C_MAYBE_CONST_EXPR around the SAVE_EXPR if needed so that c_fully_fold does not need @@ -3804,10 +3858,7 @@ c_save_expr (tree expr) expr = c_fully_fold (expr, false, &maybe_const); expr = save_expr (expr); if (!maybe_const) - { - expr = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (expr), NULL, expr); - C_MAYBE_CONST_EXPR_NON_CONST (expr) = 1; - } + expr = c_wrap_maybe_const (expr, true); return expr; } @@ -4150,6 +4201,15 @@ c_common_get_alias_set (tree t) tree u; PTR *slot; + /* For VLAs, use the alias set of the element type rather than the + default of alias set 0 for types compared structurally. */ + if (TYPE_P (t) && TYPE_STRUCTURAL_EQUALITY_P (t)) + { + if (TREE_CODE (t) == ARRAY_TYPE) + return get_alias_set (TREE_TYPE (t)); + return -1; + } + /* Permit type-punning when accessing a union, provided the access is directly through the union. For example, this code does not permit taking the address of a union member and then storing @@ -5032,44 +5092,6 @@ c_common_nodes_and_builtins (void) memset (builtin_types, 0, sizeof (builtin_types)); } -/* Look up the function in built_in_decls that corresponds to DECL - and set ASMSPEC as its user assembler name. DECL must be a - function decl that declares a builtin. */ - -void -set_builtin_user_assembler_name (tree decl, const char *asmspec) -{ - tree builtin; - gcc_assert (TREE_CODE (decl) == FUNCTION_DECL - && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL - && asmspec != 0); - - builtin = built_in_decls [DECL_FUNCTION_CODE (decl)]; - set_user_assembler_name (builtin, asmspec); - switch (DECL_FUNCTION_CODE (decl)) - { - case BUILT_IN_MEMCPY: - init_block_move_fn (asmspec); - memcpy_libfunc = set_user_assembler_libfunc ("memcpy", asmspec); - break; - case BUILT_IN_MEMSET: - init_block_clear_fn (asmspec); - memset_libfunc = set_user_assembler_libfunc ("memset", asmspec); - break; - case BUILT_IN_MEMMOVE: - memmove_libfunc = set_user_assembler_libfunc ("memmove", asmspec); - break; - case BUILT_IN_MEMCMP: - memcmp_libfunc = set_user_assembler_libfunc ("memcmp", asmspec); - break; - case BUILT_IN_ABORT: - abort_libfunc = set_user_assembler_libfunc ("abort", asmspec); - break; - default: - break; - } -} - /* The number of named compound-literals generated thus far. */ static GTY(()) int compound_literal_number; @@ -6455,9 +6477,10 @@ handle_mode_attribute (tree *node, tree name, tree args, if (POINTER_TYPE_P (type)) { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (type)); tree (*fn)(tree, enum machine_mode, bool); - if (!targetm.valid_pointer_mode (mode)) + if (!targetm.addr_space.valid_pointer_mode (mode, as)) { error ("invalid pointer mode %qs", p); return NULL_TREE; @@ -7802,6 +7825,8 @@ parse_optimize_options (tree args, bool attr_p) /* Now parse the options. */ decode_options (opt_argc, opt_argv); + targetm.override_options_after_change(); + /* Don't allow changing -fstrict-aliasing. */ flag_strict_aliasing = saved_flag_strict_aliasing; @@ -8186,7 +8211,8 @@ c_parse_error (const char *gmsgid, enum cpp_ttype token_type, else if (token_type == CPP_STRING || token_type == CPP_WSTRING || token_type == CPP_STRING16 - || token_type == CPP_STRING32) + || token_type == CPP_STRING32 + || token_type == CPP_UTF8STRING) message = catenate_messages (gmsgid, " before string constant"); else if (token_type == CPP_NUMBER) message = catenate_messages (gmsgid, " before numeric constant"); @@ -8330,15 +8356,14 @@ fold_offsetof_1 (tree expr, tree stop_ref) error ("cannot apply % when % is overloaded"); return error_mark_node; - case INTEGER_CST: - gcc_assert (integer_zerop (expr)); - return size_zero_node; - case NOP_EXPR: case INDIRECT_REF: - base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); - gcc_assert (base == error_mark_node || base == size_zero_node); - return base; + if (!integer_zerop (TREE_OPERAND (expr, 0))) + { + error ("cannot apply % to a non constant address"); + return error_mark_node; + } + return size_zero_node; case COMPONENT_REF: base = fold_offsetof_1 (TREE_OPERAND (expr, 0), stop_ref); @@ -8371,6 +8396,48 @@ fold_offsetof_1 (tree expr, tree stop_ref) } t = convert (sizetype, t); off = size_binop (MULT_EXPR, TYPE_SIZE_UNIT (TREE_TYPE (expr)), t); + + /* Check if the offset goes beyond the upper bound of the array. */ + if (code == PLUS_EXPR && TREE_CODE (t) == INTEGER_CST) + { + tree upbound = array_ref_up_bound (expr); + if (upbound != NULL_TREE + && TREE_CODE (upbound) == INTEGER_CST + && !tree_int_cst_equal (upbound, + TYPE_MAX_VALUE (TREE_TYPE (upbound)))) + { + upbound = size_binop (PLUS_EXPR, upbound, + build_int_cst (TREE_TYPE (upbound), 1)); + if (tree_int_cst_lt (upbound, t)) + { + tree v; + + for (v = TREE_OPERAND (expr, 0); + TREE_CODE (v) == COMPONENT_REF; + v = TREE_OPERAND (v, 0)) + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0))) + == RECORD_TYPE) + { + tree fld_chain = TREE_CHAIN (TREE_OPERAND (v, 1)); + for (; fld_chain; fld_chain = TREE_CHAIN (fld_chain)) + if (TREE_CODE (fld_chain) == FIELD_DECL) + break; + + if (fld_chain) + break; + } + /* Don't warn if the array might be considered a poor + man's flexible array member with a very permissive + definition thereof. */ + if (TREE_CODE (v) == ARRAY_REF + || TREE_CODE (v) == COMPONENT_REF) + warning (OPT_Warray_bounds, + "index %E denotes an offset " + "greater than size of %qT", + t, TREE_TYPE (TREE_OPERAND (expr, 0))); + } + } + } break; case COMPOUND_EXPR: @@ -8506,7 +8573,7 @@ complete_array_type (tree *ptype, tree initial_value, bool do_default) if (quals == 0) unqual_elt = elt; else - unqual_elt = c_build_qualified_type (elt, TYPE_UNQUALIFIED); + unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE (quals)); /* Using build_distinct_type_copy and modifying things afterward instead of using build_array_type to create a new type preserves all of the diff --git a/gcc/c-common.h b/gcc/c-common.h index c1655ae69ff..d91546ff239 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -126,6 +126,30 @@ enum rid RID_AT_INTERFACE, RID_AT_IMPLEMENTATION, + /* Named address support, mapping the keyword to a particular named address + number. Named address space 0 is reserved for the generic address. If + there are more than 254 named addresses, the addr_space_t type will need + to be grown from an unsigned char to unsigned short. */ + RID_ADDR_SPACE_0, /* generic address */ + RID_ADDR_SPACE_1, + RID_ADDR_SPACE_2, + RID_ADDR_SPACE_3, + RID_ADDR_SPACE_4, + RID_ADDR_SPACE_5, + RID_ADDR_SPACE_6, + RID_ADDR_SPACE_7, + RID_ADDR_SPACE_8, + RID_ADDR_SPACE_9, + RID_ADDR_SPACE_10, + RID_ADDR_SPACE_11, + RID_ADDR_SPACE_12, + RID_ADDR_SPACE_13, + RID_ADDR_SPACE_14, + RID_ADDR_SPACE_15, + + RID_FIRST_ADDR_SPACE = RID_ADDR_SPACE_0, + RID_LAST_ADDR_SPACE = RID_ADDR_SPACE_15, + RID_MAX, RID_FIRST_MODIFIER = RID_STATIC, @@ -263,6 +287,10 @@ struct c_common_resword #define D_CXX_OBJC 0x100 /* In Objective C, and C++, but not C. */ #define D_CXXWARN 0x200 /* In C warn with -Wcxx-compat. */ +/* Macro for backends to define named address keywords. */ +#define ADDR_SPACE_KEYWORD(STRING, VALUE) \ + { STRING, RID_FIRST_ADDR_SPACE + (VALUE), D_CONLY | D_EXT } + /* The reserved keyword table. */ extern const struct c_common_resword c_common_reswords[]; @@ -760,6 +788,7 @@ extern const struct attribute_spec c_common_format_attribute_table[]; extern tree (*make_fname_decl) (location_t, tree, int); +extern const char *c_addr_space_name (addr_space_t as); extern tree identifier_global_value (tree); extern void record_builtin_type (enum rid, const char *, tree); extern tree build_void_list_node (void); @@ -792,6 +821,7 @@ extern tree c_build_bitfield_integer_type (unsigned HOST_WIDE_INT, int); extern bool decl_with_nonnull_addr_p (const_tree); extern tree c_fully_fold (tree, bool, bool *); extern tree decl_constant_value_for_optimization (tree); +extern tree c_wrap_maybe_const (tree, bool); extern tree c_save_expr (tree); extern tree c_common_truthvalue_conversion (location_t, tree); extern void c_apply_type_quals_to_decl (int, tree); @@ -839,8 +869,6 @@ extern tree c_build_qualified_type (tree, int); frontends. */ extern void c_common_nodes_and_builtins (void); -extern void set_builtin_user_assembler_name (tree decl, const char *asmspec); - extern void disable_builtin_function (const char *); extern void set_compound_literal_name (tree decl); diff --git a/gcc/c-decl.c b/gcc/c-decl.c index e237332f174..492d2e673b7 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -1746,8 +1746,35 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, } else { - if (TYPE_QUALS (newtype) != TYPE_QUALS (oldtype)) - error ("conflicting type qualifiers for %q+D", newdecl); + int new_quals = TYPE_QUALS (newtype); + int old_quals = TYPE_QUALS (oldtype); + + if (new_quals != old_quals) + { + addr_space_t new_addr = DECODE_QUAL_ADDR_SPACE (new_quals); + addr_space_t old_addr = DECODE_QUAL_ADDR_SPACE (old_quals); + if (new_addr != old_addr) + { + if (ADDR_SPACE_GENERIC_P (new_addr)) + error ("conflicting named address spaces (generic vs %s) " + "for %q+D", + c_addr_space_name (old_addr), newdecl); + else if (ADDR_SPACE_GENERIC_P (old_addr)) + error ("conflicting named address spaces (%s vs generic) " + "for %q+D", + c_addr_space_name (new_addr), newdecl); + else + error ("conflicting named address spaces (%s vs %s) " + "for %q+D", + c_addr_space_name (new_addr), + c_addr_space_name (old_addr), + newdecl); + } + + if (CLEAR_QUAL_ADDR_SPACE (new_quals) + != CLEAR_QUAL_ADDR_SPACE (old_quals)) + error ("conflicting type qualifiers for %q+D", newdecl); + } else error ("conflicting types for %q+D", newdecl); diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype); @@ -3605,7 +3632,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) else if (!declspecs->tag_defined_p && (declspecs->const_p || declspecs->volatile_p - || declspecs->restrict_p)) + || declspecs->restrict_p + || declspecs->address_space)) { if (warned != 1) pedwarn (input_location, 0, @@ -3676,7 +3704,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned) if (!warned && !in_system_header && (declspecs->const_p || declspecs->volatile_p - || declspecs->restrict_p)) + || declspecs->restrict_p + || declspecs->address_space)) { warning (0, "useless type qualifier in empty declaration"); warned = 2; @@ -3699,7 +3728,8 @@ quals_from_declspecs (const struct c_declspecs *specs) { int quals = ((specs->const_p ? TYPE_QUAL_CONST : 0) | (specs->volatile_p ? TYPE_QUAL_VOLATILE : 0) - | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0)); + | (specs->restrict_p ? TYPE_QUAL_RESTRICT : 0) + | (ENCODE_QUAL_ADDR_SPACE (specs->address_space))); gcc_assert (!specs->type && !specs->decl_attr && specs->typespec_word == cts_none @@ -4750,6 +4780,7 @@ grokdeclarator (const struct c_declarator *declarator, bool bitfield = width != NULL; tree element_type; struct c_arg_info *arg_info = 0; + addr_space_t as1, as2, address_space; location_t loc = UNKNOWN_LOCATION; const char *errmsg; tree expr_dummy; @@ -4880,6 +4911,10 @@ grokdeclarator (const struct c_declarator *declarator, constp = declspecs->const_p + TYPE_READONLY (element_type); restrictp = declspecs->restrict_p + TYPE_RESTRICT (element_type); volatilep = declspecs->volatile_p + TYPE_VOLATILE (element_type); + as1 = declspecs->address_space; + as2 = TYPE_ADDR_SPACE (element_type); + address_space = ADDR_SPACE_GENERIC_P (as1)? as2 : as1; + if (pedantic && !flag_isoc99) { if (constp > 1) @@ -4889,11 +4924,17 @@ grokdeclarator (const struct c_declarator *declarator, if (volatilep > 1) pedwarn (loc, OPT_pedantic, "duplicate %"); } + + if (!ADDR_SPACE_GENERIC_P (as1) && !ADDR_SPACE_GENERIC_P (as2) && as1 != as2) + error_at (loc, "conflicting named address spaces (%s vs %s)", + c_addr_space_name (as1), c_addr_space_name (as2)); + if (!flag_gen_aux_info && (TYPE_QUALS (element_type))) type = TYPE_MAIN_VARIANT (type); type_quals = ((constp ? TYPE_QUAL_CONST : 0) | (restrictp ? TYPE_QUAL_RESTRICT : 0) - | (volatilep ? TYPE_QUAL_VOLATILE : 0)); + | (volatilep ? TYPE_QUAL_VOLATILE : 0) + | ENCODE_QUAL_ADDR_SPACE (address_space)); /* Warn about storage classes that are invalid for certain kinds of declarations (parameters, typenames, etc.). */ @@ -5309,7 +5350,14 @@ grokdeclarator (const struct c_declarator *declarator, it, but here we want to make sure we don't ever modify the shared type, so we gcc_assert (itype) below. */ - type = build_array_type (type, itype); + { + addr_space_t as = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (as) && as != TYPE_ADDR_SPACE (type)) + type = build_qualified_type (type, + ENCODE_QUAL_ADDR_SPACE (as)); + + type = build_array_type (type, itype); + } if (type != error_mark_node) { @@ -5515,6 +5563,59 @@ grokdeclarator (const struct c_declarator *declarator, /* Now TYPE has the actual type, apart from any qualifiers in TYPE_QUALS. */ + /* Warn about address space used for things other than static memory or + pointers. */ + address_space = DECODE_QUAL_ADDR_SPACE (type_quals); + if (!ADDR_SPACE_GENERIC_P (address_space)) + { + if (decl_context == NORMAL) + { + switch (storage_class) + { + case csc_auto: + error ("%qs combined with % qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_register: + error ("%qs combined with % qualifier for %qE", + c_addr_space_name (address_space), name); + break; + case csc_none: + if (current_function_scope) + { + error ("%qs specified for auto variable %qE", + c_addr_space_name (address_space), name); + break; + } + break; + case csc_static: + case csc_extern: + case csc_typedef: + break; + default: + gcc_unreachable (); + } + } + else if (decl_context == PARM && TREE_CODE (type) != ARRAY_TYPE) + { + if (name) + error ("%qs specified for parameter %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for unnamed parameter", + c_addr_space_name (address_space)); + } + else if (decl_context == FIELD) + { + if (name) + error ("%qs specified for structure field %qE", + c_addr_space_name (address_space), name); + else + error ("%qs specified for structure field", + c_addr_space_name (address_space)); + } + } + /* Check the type and width of a bit-field. */ if (bitfield) check_bitfield_type_and_width (&type, width, name); @@ -8297,9 +8398,29 @@ build_null_declspecs (void) ret->volatile_p = false; ret->restrict_p = false; ret->saturating_p = false; + ret->address_space = ADDR_SPACE_GENERIC; return ret; } +/* Add the address space ADDRSPACE to the declaration specifiers + SPECS, returning SPECS. */ + +struct c_declspecs * +declspecs_add_addrspace (struct c_declspecs *specs, addr_space_t as) +{ + specs->non_sc_seen_p = true; + specs->declspecs_seen_p = true; + + if (!ADDR_SPACE_GENERIC_P (specs->address_space) + && specs->address_space != as) + error ("incompatible address space qualifiers %qs and %qs", + c_addr_space_name (as), + c_addr_space_name (specs->address_space)); + else + specs->address_space = as; + return specs; +} + /* Add the type qualifier QUAL to the declaration specifiers SPECS, returning SPECS. */ diff --git a/gcc/c-lex.c b/gcc/c-lex.c index 0c6cdab9dff..fd3df8c0a48 100644 --- a/gcc/c-lex.c +++ b/gcc/c-lex.c @@ -365,6 +365,7 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, case CPP_WSTRING: case CPP_STRING16: case CPP_STRING32: + case CPP_UTF8STRING: type = lex_string (tok, value, true, true); break; @@ -423,7 +424,8 @@ c_lex_with_flags (tree *value, location_t *loc, unsigned char *cpp_flags, case CPP_WSTRING: case CPP_STRING16: case CPP_STRING32: - if ((lex_flags & C_LEX_RAW_STRINGS) == 0) + case CPP_UTF8STRING: + if ((lex_flags & C_LEX_STRING_NO_JOIN) == 0) { type = lex_string (tok, value, false, (lex_flags & C_LEX_STRING_NO_TRANSLATE) == 0); @@ -871,12 +873,13 @@ interpret_fixed (const cpp_token *token, unsigned int flags) return value; } -/* Convert a series of STRING, WSTRING, STRING16 and/or STRING32 tokens - into a tree, performing string constant concatenation. TOK is the - first of these. VALP is the location to write the string into. - OBJC_STRING indicates whether an '@' token preceded the incoming token. +/* Convert a series of STRING, WSTRING, STRING16, STRING32 and/or + UTF8STRING tokens into a tree, performing string constant + concatenation. TOK is the first of these. VALP is the location + to write the string into. OBJC_STRING indicates whether an '@' token + preceded the incoming token. Returns the CPP token type of the result (CPP_STRING, CPP_WSTRING, - CPP_STRING32, CPP_STRING16, or CPP_OBJC_STRING). + CPP_STRING32, CPP_STRING16, CPP_UTF8STRING, or CPP_OBJC_STRING). This is unfortunately more work than it should be. If any of the strings in the series has an L prefix, the result is a wide string @@ -921,6 +924,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) case CPP_WSTRING: case CPP_STRING16: case CPP_STRING32: + case CPP_UTF8STRING: if (type != tok->type) { if (type == CPP_STRING) @@ -966,6 +970,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) { default: case CPP_STRING: + case CPP_UTF8STRING: value = build_string (1, ""); break; case CPP_STRING16: @@ -991,6 +996,7 @@ lex_string (const cpp_token *tok, tree *valp, bool objc_string, bool translate) { default: case CPP_STRING: + case CPP_UTF8STRING: TREE_TYPE (value) = char_array_type_node; break; case CPP_STRING16: diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 3f6e949fe8e..1a6012e9128 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -72,6 +72,10 @@ c_parse_init (void) tree id; int mask = 0; + /* Make sure RID_MAX hasn't grown past the 8 bits used to hold the keyword in + the c_token structure. */ + gcc_assert (RID_MAX <= 255); + mask |= D_CXXONLY; if (!flag_isoc99) mask |= D_C99; @@ -132,6 +136,8 @@ typedef enum c_id_kind { C_ID_TYPENAME, /* An identifier declared as an Objective-C class name. */ C_ID_CLASSNAME, + /* An address space identifier. */ + C_ID_ADDRSPACE, /* Not an identifier. */ C_ID_NONE } c_id_kind; @@ -226,6 +232,13 @@ c_lex_one_token (c_parser *parser, c_token *token) "identifier %qE conflicts with C++ keyword", token->value); } + else if (rid_code >= RID_FIRST_ADDR_SPACE + && rid_code <= RID_LAST_ADDR_SPACE) + { + token->id_kind = C_ID_ADDRSPACE; + token->keyword = rid_code; + break; + } else if (c_dialect_objc ()) { if (!objc_is_reserved_word (token->value) @@ -352,6 +365,8 @@ c_token_starts_typename (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -422,6 +437,8 @@ c_token_starts_declspecs (c_token *token) { case C_ID_ID: return false; + case C_ID_ADDRSPACE: + return true; case C_ID_TYPENAME: return true; case C_ID_CLASSNAME: @@ -1411,6 +1428,7 @@ c_parser_asm_definition (c_parser *parser) const restrict volatile + address-space-qualifier (restrict is new in C99.) @@ -1419,6 +1437,12 @@ c_parser_asm_definition (c_parser *parser) declaration-specifiers: attributes declaration-specifiers[opt] + type-qualifier: + address-space + + address-space: + identifier recognized by the target + storage-class-specifier: __thread @@ -1459,6 +1483,17 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs, { tree value = c_parser_peek_token (parser)->value; c_id_kind kind = c_parser_peek_token (parser)->id_kind; + + if (kind == C_ID_ADDRSPACE) + { + addr_space_t as + = c_parser_peek_token (parser)->keyword - RID_FIRST_ADDR_SPACE; + declspecs_add_addrspace (specs, as); + c_parser_consume_token (parser); + attrs_ok = true; + continue; + } + /* This finishes the specifiers unless a type name is OK, it is declared as a type name and a type name hasn't yet been seen. */ @@ -5349,6 +5384,7 @@ c_parser_postfix_expression (c_parser *parser) case CPP_STRING16: case CPP_STRING32: case CPP_WSTRING: + case CPP_UTF8STRING: expr.value = c_parser_peek_token (parser)->value; expr.original_code = STRING_CST; c_parser_consume_token (parser); @@ -5774,6 +5810,14 @@ c_parser_postfix_expression_after_paren_type (c_parser *parser, finish_init (); maybe_warn_string_init (type, init); + if (type != error_mark_node + && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)) + && current_function_decl) + { + error ("compound literal qualified by address-space qualifier"); + type = error_mark_node; + } + if (!flag_isoc99) pedwarn (start_loc, OPT_pedantic, "ISO C90 forbids compound literals"); non_const = ((init.value && TREE_CODE (init.value) == CONSTRUCTOR) diff --git a/gcc/c-ppoutput.c b/gcc/c-ppoutput.c index ff3e6b6c843..bd9af2aa0f6 100644 --- a/gcc/c-ppoutput.c +++ b/gcc/c-ppoutput.c @@ -61,6 +61,8 @@ static void dump_queued_macros (cpp_reader *); static void print_line (source_location, const char *); static void maybe_print_line (source_location); +static void do_line_change (cpp_reader *, const cpp_token *, + source_location, int); /* Callback routines for the parser. Most of these are active only in specific modes. */ @@ -160,11 +162,16 @@ static void scan_translation_unit (cpp_reader *pfile) { bool avoid_paste = false; + bool do_line_adjustments + = cpp_get_options (parse_in)->lang != CLK_ASM + && !flag_no_line_commands; + bool in_pragma = false; print.source = NULL; for (;;) { - const cpp_token *token = cpp_get_token (pfile); + source_location loc; + const cpp_token *token = cpp_get_token_with_location (pfile, &loc); if (token->type == CPP_PADDING) { @@ -182,16 +189,38 @@ scan_translation_unit (cpp_reader *pfile) /* Subtle logic to output a space if and only if necessary. */ if (avoid_paste) { + const struct line_map *map + = linemap_lookup (line_table, loc); + int src_line = SOURCE_LINE (map, loc); + if (print.source == NULL) print.source = token; - if (print.source->flags & PREV_WHITE - || (print.prev - && cpp_avoid_paste (pfile, print.prev, token)) - || (print.prev == NULL && token->type == CPP_HASH)) + + if (src_line != print.src_line + && do_line_adjustments + && !in_pragma) + { + do_line_change (pfile, token, loc, false); + putc (' ', print.outf); + } + else if (print.source->flags & PREV_WHITE + || (print.prev + && cpp_avoid_paste (pfile, print.prev, token)) + || (print.prev == NULL && token->type == CPP_HASH)) putc (' ', print.outf); } else if (token->flags & PREV_WHITE) - putc (' ', print.outf); + { + const struct line_map *map + = linemap_lookup (line_table, loc); + int src_line = SOURCE_LINE (map, loc); + + if (src_line != print.src_line + && do_line_adjustments + && !in_pragma) + do_line_change (pfile, token, loc, false); + putc (' ', print.outf); + } avoid_paste = false; print.source = NULL; @@ -209,9 +238,13 @@ scan_translation_unit (cpp_reader *pfile) else fprintf (print.outf, "%s", name); print.printed = 1; + in_pragma = true; } else if (token->type == CPP_PRAGMA_EOL) - maybe_print_line (token->src_loc); + { + maybe_print_line (token->src_loc); + in_pragma = false; + } else cpp_output_token (token, print.outf); @@ -331,14 +364,11 @@ print_line (source_location src_loc, const char *special_flags) } } -/* Called when a line of output is started. TOKEN is the first token - of the line, and at end of file will be CPP_EOF. */ +/* Helper function for cb_line_change and scan_translation_unit. */ static void -cb_line_change (cpp_reader *pfile, const cpp_token *token, - int parsing_args) +do_line_change (cpp_reader *pfile, const cpp_token *token, + source_location src_loc, int parsing_args) { - source_location src_loc = token->src_loc; - if (define_queue || undef_queue) dump_queued_macros (pfile); @@ -365,6 +395,15 @@ cb_line_change (cpp_reader *pfile, const cpp_token *token, } } +/* Called when a line of output is started. TOKEN is the first token + of the line, and at end of file will be CPP_EOF. */ +static void +cb_line_change (cpp_reader *pfile, const cpp_token *token, + int parsing_args) +{ + do_line_change (pfile, token, token->src_loc, parsing_args); +} + static void cb_ident (cpp_reader *pfile ATTRIBUTE_UNUSED, source_location line, const cpp_string *str) diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c index b707d165944..f71399fa93e 100644 --- a/gcc/c-pragma.c +++ b/gcc/c-pragma.c @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "diagnostic.h" #include "opts.h" +#include "plugin.h" #define GCC_BAD(gmsgid) \ do { warning (OPT_Wpragmas, gmsgid); return; } while (0) @@ -723,19 +724,20 @@ maybe_apply_renaming_pragma (tree decl, tree asmname) #ifdef HANDLE_PRAGMA_VISIBILITY static void handle_pragma_visibility (cpp_reader *); -typedef enum symbol_visibility visibility; -DEF_VEC_I (visibility); -DEF_VEC_ALLOC_I (visibility, heap); -static VEC (visibility, heap) *visstack; +static VEC (int, heap) *visstack; /* Push the visibility indicated by STR onto the top of the #pragma - visibility stack. */ + visibility stack. KIND is 0 for #pragma GCC visibility, 1 for + C++ namespace with visibility attribute and 2 for C++ builtin + ABI namespace. push_visibility/pop_visibility calls must have + matching KIND, it is not allowed to push visibility using one + KIND and pop using a different one. */ void -push_visibility (const char *str) +push_visibility (const char *str, int kind) { - VEC_safe_push (visibility, heap, visstack, - default_visibility); + VEC_safe_push (int, heap, visstack, + ((int) default_visibility) | (kind << 8)); if (!strcmp (str, "default")) default_visibility = VISIBILITY_DEFAULT; else if (!strcmp (str, "internal")) @@ -749,14 +751,21 @@ push_visibility (const char *str) visibility_options.inpragma = 1; } -/* Pop a level of the #pragma visibility stack. */ +/* Pop a level of the #pragma visibility stack. Return true if + successful. */ -void -pop_visibility (void) +bool +pop_visibility (int kind) { - default_visibility = VEC_pop (visibility, visstack); + if (!VEC_length (int, visstack)) + return false; + if ((VEC_last (int, visstack) >> 8) != kind) + return false; + default_visibility + = (enum symbol_visibility) (VEC_pop (int, visstack) & 0xff); visibility_options.inpragma - = VEC_length (visibility, visstack) != 0; + = VEC_length (int, visstack) != 0; + return true; } /* Sets the default visibility for symbols to something other than that @@ -785,10 +794,8 @@ handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED) { if (pop == action) { - if (!VEC_length (visibility, visstack)) + if (! pop_visibility (0)) GCC_BAD ("no matching push for %<#pragma GCC visibility pop%>"); - else - pop_visibility (); } else { @@ -798,7 +805,7 @@ handle_pragma_visibility (cpp_reader *dummy ATTRIBUTE_UNUSED) if (token != CPP_NAME) GCC_BAD ("malformed #pragma GCC visibility push"); else - push_visibility (IDENTIFIER_POINTER (x)); + push_visibility (IDENTIFIER_POINTER (x), 0); if (pragma_lex (&x) != CPP_CLOSE_PAREN) GCC_BAD ("missing %<(%> after %<#pragma GCC visibility push%> - ignored"); } @@ -1444,6 +1451,9 @@ init_pragma (void) #ifdef REGISTER_TARGET_PRAGMAS REGISTER_TARGET_PRAGMAS (); #endif + + /* Allow plugins to register their own pragmas. */ + invoke_plugin_callbacks (PLUGIN_PRAGMAS, NULL); } #include "gt-c-pragma.h" diff --git a/gcc/c-pragma.h b/gcc/c-pragma.h index 188afb8dbaa..eab23db6cd9 100644 --- a/gcc/c-pragma.h +++ b/gcc/c-pragma.h @@ -95,8 +95,8 @@ extern struct cpp_reader* parse_in; visibility is not supported on the host OS platform the statements are ignored. */ #define HANDLE_PRAGMA_VISIBILITY 1 -extern void push_visibility (const char *); -extern void pop_visibility (void); +extern void push_visibility (const char *, int); +extern bool pop_visibility (int); extern void init_pragma (void); @@ -118,9 +118,9 @@ extern enum cpp_ttype pragma_lex (tree *); so that 0 means to translate and join strings. */ #define C_LEX_STRING_NO_TRANSLATE 1 /* Do not lex strings into execution character set. */ -#define C_LEX_RAW_STRINGS 2 /* Return raw strings -- no - concatenation, no - translation. */ +#define C_LEX_STRING_NO_JOIN 2 /* Do not concatenate strings + nor translate them into execution + character set. */ /* This is not actually available to pragma parsers. It's merely a convenient location to declare this function for c-lex, after diff --git a/gcc/c-pretty-print.c b/gcc/c-pretty-print.c index c4e6e96c296..01770014c21 100644 --- a/gcc/c-pretty-print.c +++ b/gcc/c-pretty-print.c @@ -225,7 +225,11 @@ pp_c_space_for_pointer_operator (c_pretty_printer *pp, tree t) const restrict -- C99 __restrict__ -- GNU C - volatile */ + address-space-qualifier -- GNU C + volatile + + address-space-qualifier: + identifier -- GNU C */ void pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) @@ -245,6 +249,12 @@ pp_c_type_qualifier_list (c_pretty_printer *pp, tree t) pp_c_cv_qualifier (pp, "volatile"); if (qualifiers & TYPE_QUAL_RESTRICT) pp_c_cv_qualifier (pp, flag_isoc99 ? "restrict" : "__restrict__"); + + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (t))) + { + const char *as = c_addr_space_name (TYPE_ADDR_SPACE (t)); + pp_c_identifier (pp, as); + } } /* pointer: diff --git a/gcc/c-tree.h b/gcc/c-tree.h index c7490e461a3..e71771ae840 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -277,6 +277,8 @@ struct c_declspecs { BOOL_BITFIELD restrict_p : 1; /* Whether "_Sat" was specified. */ BOOL_BITFIELD saturating_p : 1; + /* The address space that the declaration belongs to. */ + addr_space_t address_space; }; /* The various kinds of declarators in C. */ @@ -476,6 +478,8 @@ extern struct c_declspecs *declspecs_add_type (location_t, struct c_typespec); extern struct c_declspecs *declspecs_add_scspec (struct c_declspecs *, tree); extern struct c_declspecs *declspecs_add_attrs (struct c_declspecs *, tree); +extern struct c_declspecs *declspecs_add_addrspace (struct c_declspecs *, + addr_space_t); extern struct c_declspecs *finish_declspecs (struct c_declspecs *); /* in c-objc-common.c */ diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 4c55e587de3..9b1f09c4593 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -284,14 +284,55 @@ c_type_promotes_to (tree type) return type; } +/* Return true if between two named address spaces, whether there is a superset + named address space that encompasses both address spaces. If there is a + superset, return which address space is the superset. */ + +static bool +addr_space_superset (addr_space_t as1, addr_space_t as2, addr_space_t *common) +{ + if (as1 == as2) + { + *common = as1; + return true; + } + else if (targetm.addr_space.subset_p (as1, as2)) + { + *common = as2; + return true; + } + else if (targetm.addr_space.subset_p (as2, as1)) + { + *common = as1; + return true; + } + else + return false; +} + /* Return a variant of TYPE which has all the type qualifiers of LIKE as well as those of TYPE. */ static tree qualify_type (tree type, tree like) { + addr_space_t as_type = TYPE_ADDR_SPACE (type); + addr_space_t as_like = TYPE_ADDR_SPACE (like); + addr_space_t as_common; + + /* If the two named address spaces are different, determine the common + superset address space. If there isn't one, raise an error. */ + if (!addr_space_superset (as_type, as_like, &as_common)) + { + as_common = as_type; + error ("%qT and %qT are in disjoint named address spaces", + type, like); + } + return c_build_qualified_type (type, - TYPE_QUALS (type) | TYPE_QUALS (like)); + TYPE_QUALS_NO_ADDR_SPACE (type) + | TYPE_QUALS_NO_ADDR_SPACE (like) + | ENCODE_QUAL_ADDR_SPACE (as_common)); } /* Return true iff the given tree T is a variable length array. */ @@ -371,7 +412,8 @@ composite_type (tree t1, tree t2) bool t1_complete, t2_complete; /* We should not have any type quals on arrays at all. */ - gcc_assert (!TYPE_QUALS (t1) && !TYPE_QUALS (t2)); + gcc_assert (!TYPE_QUALS_NO_ADDR_SPACE (t1) + && !TYPE_QUALS_NO_ADDR_SPACE (t2)); t1_complete = COMPLETE_TYPE_P (t1); t2_complete = COMPLETE_TYPE_P (t2); @@ -585,6 +627,8 @@ common_pointer_type (tree t1, tree t2) tree pointed_to_2, mv2; tree target; unsigned target_quals; + addr_space_t as1, as2, as_common; + int quals1, quals2; /* Save time if the two types are the same. */ @@ -616,10 +660,24 @@ common_pointer_type (tree t1, tree t2) /* For function types do not merge const qualifiers, but drop them if used inconsistently. The middle-end uses these to mark const and noreturn functions. */ + quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1); + quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2); + if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE) - target_quals = TYPE_QUALS (pointed_to_1) & TYPE_QUALS (pointed_to_2); + target_quals = (quals1 & quals2); else - target_quals = TYPE_QUALS (pointed_to_1) | TYPE_QUALS (pointed_to_2); + target_quals = (quals1 | quals2); + + /* If the two named address spaces are different, determine the common + superset address space. This is guaranteed to exist due to the + assumption that comp_target_type returned non-zero. */ + as1 = TYPE_ADDR_SPACE (pointed_to_1); + as2 = TYPE_ADDR_SPACE (pointed_to_2); + if (!addr_space_superset (as1, as2, &as_common)) + gcc_unreachable (); + + target_quals |= ENCODE_QUAL_ADDR_SPACE (as_common); + t1 = build_pointer_type (c_build_qualified_type (target, target_quals)); return build_type_attribute_variant (t1, attributes); } @@ -1103,20 +1161,28 @@ comptypes_internal (const_tree type1, const_tree type2, bool *enum_and_int_p) return attrval == 2 && val == 1 ? 2 : val; } -/* Return 1 if TTL and TTR are pointers to types that are equivalent, - ignoring their qualifiers. */ +/* Return 1 if TTL and TTR are pointers to types that are equivalent, ignoring + their qualifiers, except for named address spaces. If the pointers point to + different named addresses, then we must determine if one address space is a + subset of the other. */ static int comp_target_types (location_t location, tree ttl, tree ttr) { int val; - tree mvl, mvr; + tree mvl = TREE_TYPE (ttl); + tree mvr = TREE_TYPE (ttr); + addr_space_t asl = TYPE_ADDR_SPACE (mvl); + addr_space_t asr = TYPE_ADDR_SPACE (mvr); + addr_space_t as_common; bool enum_and_int_p; + /* Fail if pointers point to incompatible address spaces. */ + if (!addr_space_superset (asl, asr, &as_common)) + return 0; + /* Do not lose qualifiers on element types of array types that are pointer targets by taking their TYPE_MAIN_VARIANT. */ - mvl = TREE_TYPE (ttl); - mvr = TREE_TYPE (ttr); if (TREE_CODE (mvl) != ARRAY_TYPE) mvl = TYPE_MAIN_VARIANT (mvl); if (TREE_CODE (mvr) != ARRAY_TYPE) @@ -2673,6 +2739,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, { tree typetail, val; unsigned int parmnum; + bool error_args = false; const bool type_generic = fundecl && lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl))); bool type_generic_remove_excess_precision = false; @@ -2942,6 +3009,8 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, parmval = default_conversion (val); VEC_replace (tree, values, parmnum, parmval); + if (parmval == error_mark_node) + error_args = true; if (typetail) typetail = TREE_CHAIN (typetail); @@ -2955,7 +3024,7 @@ convert_arguments (tree typelist, VEC(tree,gc) *values, return -1; } - return parmnum; + return error_args ? -1 : (int) parmnum; } /* This is the entry point used by the parser to build unary operators @@ -3063,11 +3132,43 @@ static tree pointer_diff (location_t loc, tree op0, tree op1) { tree restype = ptrdiff_type_node; + tree result, inttype; + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op0))); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (op1))); tree target_type = TREE_TYPE (TREE_TYPE (op0)); tree con0, con1, lit0, lit1; tree orig_op1 = op1; + /* If the operands point into different address spaces, we need to + explicitly convert them to pointers into the common address space + before we can subtract the numerical address values. */ + if (as0 != as1) + { + addr_space_t as_common; + tree common_type; + + /* Determine the common superset address space. This is guaranteed + to exist because the caller verified that comp_target_types + returned non-zero. */ + if (!addr_space_superset (as0, as1, &as_common)) + gcc_unreachable (); + + common_type = common_pointer_type (TREE_TYPE (op0), TREE_TYPE (op1)); + op0 = convert (common_type, op0); + op1 = convert (common_type, op1); + } + + /* Determine integer type to perform computations in. This will usually + be the same as the result type (ptrdiff_t), but may need to be a wider + type if pointers for the address space are wider than ptrdiff_t. */ + if (TYPE_PRECISION (restype) < TYPE_PRECISION (TREE_TYPE (op0))) + inttype = lang_hooks.types.type_for_size + (TYPE_PRECISION (TREE_TYPE (op0)), 0); + else + inttype = restype; + + if (TREE_CODE (target_type) == VOID_TYPE) pedwarn (loc, pedantic ? OPT_pedantic : OPT_Wpointer_arith, "pointer of type % used in subtraction"); @@ -3125,8 +3226,8 @@ pointer_diff (location_t loc, tree op0, tree op1) in case restype is a short type. */ op0 = build_binary_op (loc, - MINUS_EXPR, convert (restype, op0), - convert (restype, op1), 0); + MINUS_EXPR, convert (inttype, op0), + convert (inttype, op1), 0); /* This generates an error if op1 is pointer to incomplete type. */ if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (orig_op1)))) error_at (loc, "arithmetic on pointer to an incomplete type"); @@ -3135,8 +3236,11 @@ pointer_diff (location_t loc, tree op0, tree op1) op1 = c_size_in_bytes (target_type); /* Divide by the size, in easiest possible way. */ - return fold_build2_loc (loc, EXACT_DIV_EXPR, restype, - op0, convert (restype, op1)); + result = fold_build2_loc (loc, EXACT_DIV_EXPR, inttype, + op0, convert (inttype, op1)); + + /* Convert to final result type if necessary. */ + return convert (restype, result); } /* Construct and perhaps optimize a tree representation @@ -3940,17 +4044,9 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, "conditional expression")); } if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) - { - op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1), - NULL, op1); - C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const; - } + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); if (!op2_maybe_const || TREE_CODE (op2) != INTEGER_CST) - { - op2 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op2), - NULL, op2); - C_MAYBE_CONST_EXPR_NON_CONST (op2) = !op2_maybe_const; - } + op2 = c_wrap_maybe_const (op2, !op2_maybe_const); } } } @@ -3964,12 +4060,22 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, } else if (code1 == POINTER_TYPE && code2 == POINTER_TYPE) { + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as2 = TYPE_ADDR_SPACE (TREE_TYPE (type2)); + addr_space_t as_common; + if (comp_target_types (colon_loc, type1, type2)) result_type = common_pointer_type (type1, type2); else if (null_pointer_constant_p (orig_op1)) - result_type = qualify_type (type2, type1); + result_type = type2; else if (null_pointer_constant_p (orig_op2)) - result_type = qualify_type (type1, type2); + result_type = type1; + else if (!addr_space_superset (as1, as2, &as_common)) + { + error_at (colon_loc, "pointers to disjoint address spaces " + "used in conditional expression"); + return error_mark_node; + } else if (VOID_TYPE_P (TREE_TYPE (type1))) { if (TREE_CODE (TREE_TYPE (type2)) == FUNCTION_TYPE) @@ -3990,10 +4096,13 @@ build_conditional_expr (location_t colon_loc, tree ifexp, bool ifexp_bcp, } else { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + if (!objc_ok) pedwarn (colon_loc, 0, "pointer type mismatch in conditional expression"); - result_type = build_pointer_type (void_type_node); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); } } else if (code1 == POINTER_TYPE && code2 == INTEGER_TYPE) @@ -4152,7 +4261,8 @@ build_compound_expr (location_t loc, tree expr1, tree expr2) /* Issue -Wcast-qual warnings when appropriate. TYPE is the type to which we are casting. OTYPE is the type of the expression being cast. Both TYPE and OTYPE are pointer types. -Wcast-qual appeared - on the command line. */ + on the command line. Named address space qualifiers are not handled + here, because they result in different warnings. */ static void handle_warn_cast_qual (tree type, tree otype) @@ -4178,9 +4288,11 @@ handle_warn_cast_qual (tree type, tree otype) taken away. */ if (TREE_CODE (in_otype) == FUNCTION_TYPE && TREE_CODE (in_type) == FUNCTION_TYPE) - added |= (TYPE_QUALS (in_type) & ~TYPE_QUALS (in_otype)); + added |= (TYPE_QUALS_NO_ADDR_SPACE (in_type) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_otype)); else - discarded |= (TYPE_QUALS (in_otype) & ~TYPE_QUALS (in_type)); + discarded |= (TYPE_QUALS_NO_ADDR_SPACE (in_otype) + & ~TYPE_QUALS_NO_ADDR_SPACE (in_type)); } while (TREE_CODE (in_type) == POINTER_TYPE && TREE_CODE (in_otype) == POINTER_TYPE); @@ -4329,6 +4441,36 @@ build_c_cast (location_t loc, tree type, tree expr) && TREE_CODE (otype) == POINTER_TYPE) handle_warn_cast_qual (type, otype); + /* Warn about conversions between pointers to disjoint + address spaces. */ + if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (otype) == POINTER_TYPE + && !null_pointer_constant_p (value)) + { + addr_space_t as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); + addr_space_t as_from = TYPE_ADDR_SPACE (TREE_TYPE (otype)); + addr_space_t as_common; + + if (!addr_space_superset (as_to, as_from, &as_common)) + { + if (ADDR_SPACE_GENERIC_P (as_from)) + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint generic address space pointer", + c_addr_space_name (as_to)); + + else if (ADDR_SPACE_GENERIC_P (as_to)) + warning_at (loc, 0, "cast to generic address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_from)); + + else + warning_at (loc, 0, "cast to %s address space pointer " + "from disjoint %s address space pointer", + c_addr_space_name (as_to), + c_addr_space_name (as_from)); + } + } + /* Warn about possible alignment problems. */ if (STRICT_ALIGNMENT && TREE_CODE (type) == POINTER_TYPE @@ -4923,7 +5065,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, certain things, it is okay to use a const or volatile function where an ordinary one is wanted, but not vice-versa. */ - if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE " "makes qualified function " @@ -4937,7 +5080,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, G_("return makes qualified function " "pointer from unqualified")); } - else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + else if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE discards " "qualifiers from pointer target type"), @@ -4970,6 +5114,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, tree mvr = ttr; bool is_opaque_pointer; int target_cmp = 0; /* Cache comp_target_types () result. */ + addr_space_t asl; + addr_space_t asr; if (TREE_CODE (mvl) != ARRAY_TYPE) mvl = TYPE_MAIN_VARIANT (mvl); @@ -4990,6 +5136,36 @@ convert_for_assignment (location_t location, tree type, tree rhs, "request for implicit conversion " "from %qT to %qT not permitted in C++", rhstype, type); + /* See if the pointers point to incompatible address spaces. */ + asl = TYPE_ADDR_SPACE (ttl); + asr = TYPE_ADDR_SPACE (ttr); + if (!null_pointer_constant_p (rhs) + && asr != asl && !targetm.addr_space.subset_p (asr, asl)) + { + switch (errtype) + { + case ic_argpass: + error_at (location, "passing argument %d of %qE from pointer to " + "non-enclosed address space", parmnum, rname); + break; + case ic_assign: + error_at (location, "assignment from pointer to " + "non-enclosed address space"); + break; + case ic_init: + error_at (location, "initialization from pointer to " + "non-enclosed address space"); + break; + case ic_return: + error_at (location, "return from pointer to " + "non-enclosed address space"); + break; + default: + gcc_unreachable (); + } + return error_mark_node; + } + /* Check if the right-hand side has a format attribute but the left-hand side doesn't. */ if (warn_missing_format_attribute @@ -5053,7 +5229,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, else if (TREE_CODE (ttr) != FUNCTION_TYPE && TREE_CODE (ttl) != FUNCTION_TYPE) { - if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttr) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttl)) { /* Types differing only by the presence of the 'volatile' qualifier are acceptable if the 'volatile' has been added @@ -5093,7 +5270,8 @@ convert_for_assignment (location_t location, tree type, tree rhs, that say the function will not do certain things, it is okay to use a const or volatile function where an ordinary one is wanted, but not vice-versa. */ - if (TYPE_QUALS (ttl) & ~TYPE_QUALS (ttr)) + if (TYPE_QUALS_NO_ADDR_SPACE (ttl) + & ~TYPE_QUALS_NO_ADDR_SPACE (ttr)) WARN_FOR_ASSIGNMENT (location, 0, G_("passing argument %d of %qE makes " "qualified function pointer " @@ -8661,16 +8839,17 @@ c_finish_stmt_expr (location_t loc, tree body) goto continue_searching; } + if (last == error_mark_node) + return last; + /* In the case that the BIND_EXPR is not necessary, return the expression out from inside it. */ - if (last == error_mark_node - || (last == BIND_EXPR_BODY (body) - && BIND_EXPR_VARS (body) == NULL)) + if (last == BIND_EXPR_BODY (body) + && BIND_EXPR_VARS (body) == NULL) { /* Even if this looks constant, do not allow it in a constant expression. */ - last = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (last), NULL_TREE, last); - C_MAYBE_CONST_EXPR_NON_CONST (last) = 1; + last = c_wrap_maybe_const (last, true); /* Do not warn if the return value of a statement expression is unused. */ TREE_NO_WARNING (last) = 1; @@ -9200,24 +9379,34 @@ build_binary_op (location_t location, enum tree_code code, { tree tt0 = TREE_TYPE (type0); tree tt1 = TREE_TYPE (type1); + addr_space_t as0 = TYPE_ADDR_SPACE (tt0); + addr_space_t as1 = TYPE_ADDR_SPACE (tt1); + addr_space_t as_common = ADDR_SPACE_GENERIC; + /* Anything compares with void *. void * compares with anything. Otherwise, the targets must be compatible and both must be object or both incomplete. */ if (comp_target_types (location, type0, type1)) result_type = common_pointer_type (type0, type1); + else if (null_pointer_constant_p (orig_op0)) + result_type = type1; + else if (null_pointer_constant_p (orig_op1)) + result_type = type0; + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } else if (VOID_TYPE_P (tt0)) { - /* op0 != orig_op0 detects the case of something - whose value is 0 but which isn't a valid null ptr const. */ - if (pedantic && !null_pointer_constant_p (orig_op0) - && TREE_CODE (tt1) == FUNCTION_TYPE) + if (pedantic && TREE_CODE (tt1) == FUNCTION_TYPE) pedwarn (location, OPT_pedantic, "ISO C forbids " "comparison of % with function pointer"); } else if (VOID_TYPE_P (tt1)) { - if (pedantic && !null_pointer_constant_p (orig_op1) - && TREE_CODE (tt0) == FUNCTION_TYPE) + if (pedantic && TREE_CODE (tt0) == FUNCTION_TYPE) pedwarn (location, OPT_pedantic, "ISO C forbids " "comparison of % with function pointer"); } @@ -9228,7 +9417,11 @@ build_binary_op (location_t location, enum tree_code code, "comparison of distinct pointer types lacks a cast"); if (result_type == NULL_TREE) - result_type = ptr_type_node; + { + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); + } } else if (code0 == POINTER_TYPE && null_pointer_constant_p (orig_op1)) { @@ -9272,6 +9465,10 @@ build_binary_op (location_t location, enum tree_code code, short_compare = 1; else if (code0 == POINTER_TYPE && code1 == POINTER_TYPE) { + addr_space_t as0 = TYPE_ADDR_SPACE (TREE_TYPE (type0)); + addr_space_t as1 = TYPE_ADDR_SPACE (TREE_TYPE (type1)); + addr_space_t as_common; + if (comp_target_types (location, type0, type1)) { result_type = common_pointer_type (type0, type1); @@ -9283,9 +9480,17 @@ build_binary_op (location_t location, enum tree_code code, pedwarn (location, OPT_pedantic, "ISO C forbids " "ordered comparisons of pointers to functions"); } + else if (!addr_space_superset (as0, as1, &as_common)) + { + error_at (location, "comparison of pointers to " + "disjoint address spaces"); + return error_mark_node; + } else { - result_type = ptr_type_node; + int qual = ENCODE_QUAL_ADDR_SPACE (as_common); + result_type = build_pointer_type + (build_qualified_type (void_type_node, qual)); pedwarn (location, 0, "comparison of distinct pointer types lacks a cast"); } @@ -9545,17 +9750,9 @@ build_binary_op (location_t location, enum tree_code code, if (!in_late_binary_op) { if (!op0_maybe_const || TREE_CODE (op0) != INTEGER_CST) - { - op0 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op0), - NULL, op0); - C_MAYBE_CONST_EXPR_NON_CONST (op0) = !op0_maybe_const; - } + op0 = c_wrap_maybe_const (op0, !op0_maybe_const); if (!op1_maybe_const || TREE_CODE (op1) != INTEGER_CST) - { - op1 = build2 (C_MAYBE_CONST_EXPR, TREE_TYPE (op1), - NULL, op1); - C_MAYBE_CONST_EXPR_NON_CONST (op1) = !op1_maybe_const; - } + op1 = c_wrap_maybe_const (op1, !op1_maybe_const); } } } diff --git a/gcc/c.opt b/gcc/c.opt index 21f7ab71246..429c035f38f 100644 --- a/gcc/c.opt +++ b/gcc/c.opt @@ -113,11 +113,11 @@ C ObjC C++ ObjC++ Joined Separate -U Undefine Wabi -C ObjC C++ ObjC++ Var(warn_abi) Warning +C ObjC C++ ObjC++ LTO Var(warn_abi) Warning Warn about things that will change when compiling with an ABI-compliant compiler Wpsabi -C ObjC C++ ObjC++ Var(warn_psabi) Init(1) Undocumented +C ObjC C++ ObjC++ LTO Var(warn_psabi) Init(1) Undocumented Waddress C ObjC C++ ObjC++ Var(warn_address) Warning @@ -285,7 +285,7 @@ C ObjC C++ ObjC++ Warning Warn about PCH files that are found but not used Wjump-misses-init -C Objc Var(warn_jump_misses_init) Init(-1) Warning +C ObjC Var(warn_jump_misses_init) Init(-1) Warning Warn when a jump misses a variable initialization Wlogical-op diff --git a/gcc/calls.c b/gcc/calls.c index f28fb513ce2..13167a620a4 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "sbitmap.h" #include "langhooks.h" #include "target.h" +#include "debug.h" #include "cgraph.h" #include "except.h" #include "dbgcnt.h" @@ -394,6 +395,11 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0); + /* Record debug information for virtual calls. */ + if (flag_enable_icf_debug && fndecl == NULL) + (*debug_hooks->virtual_call_token) (CALL_EXPR_FN (fntree), + INSN_UID (call_insn)); + /* Restore this now, so that we do defer pops for this call's args if the context of the call as a whole permits. */ inhibit_defer_pop = old_inhibit_defer_pop; @@ -3014,7 +3020,10 @@ expand_call (tree exp, rtx target, int ignore) } else if (TYPE_MODE (rettype) == BLKmode) { - target = copy_blkmode_from_reg (target, valreg, rettype); + rtx val = valreg; + if (GET_MODE (val) != BLKmode) + val = avoid_likely_spilled_reg (val); + target = copy_blkmode_from_reg (target, val, rettype); /* We can not support sibling calls for this case. */ sibcall_failure = 1; diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c index cfb19b60275..ffe36e45a9e 100644 --- a/gcc/cfgcleanup.c +++ b/gcc/cfgcleanup.c @@ -958,7 +958,7 @@ old_insns_match_p (int mode ATTRIBUTE_UNUSED, rtx i1, rtx i2) if (NOTE_INSN_BASIC_BLOCK_P (i1) && NOTE_INSN_BASIC_BLOCK_P (i2)) return true; - p1 = PATTERN (i1); + p1 = PATTERN (i1); p2 = PATTERN (i2); if (GET_CODE (p1) != GET_CODE (p2)) @@ -1814,6 +1814,24 @@ try_crossjump_bb (int mode, basic_block bb) return changed; } +/* Return true if BB contains just bb note, or bb note followed + by only DEBUG_INSNs. */ + +static bool +trivially_empty_bb_p (basic_block bb) +{ + rtx insn = BB_END (bb); + + while (1) + { + if (insn == BB_HEAD (bb)) + return true; + if (!DEBUG_INSN_P (insn)) + return false; + insn = PREV_INSN (insn); + } +} + /* Do simple CFG optimizations - basic block merging, simplifying of jump instructions etc. Return nonzero if changes were made. */ @@ -1865,14 +1883,10 @@ try_optimize_cfg (int mode) __builtin_unreachable (). */ if (EDGE_COUNT (b->preds) == 0 || (EDGE_COUNT (b->succs) == 0 - && BB_HEAD (b) == BB_END (b) + && trivially_empty_bb_p (b) && single_succ_edge (ENTRY_BLOCK_PTR)->dest != b)) { c = b->prev_bb; - if (dump_file) - fprintf (dump_file, "Deleting block %i.\n", - b->index); - delete_basic_block (b); if (!(mode & CLEANUP_CFGLAYOUT)) changed = true; diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 2117ee3bc52..cfb4d17dc20 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -1768,10 +1768,10 @@ expand_call_stmt (gimple stmt) for (i = 0; i < gimple_call_num_args (stmt); i++) CALL_EXPR_ARG (exp, i) = gimple_call_arg (stmt, i); - if (!(gimple_call_flags (stmt) & (ECF_CONST | ECF_PURE))) + if (gimple_has_side_effects (stmt)) TREE_SIDE_EFFECTS (exp) = 1; - if (gimple_call_flags (stmt) & ECF_NOTHROW) + if (gimple_call_nothrow_p (stmt)) TREE_NOTHROW (exp) = 1; CALL_EXPR_TAILCALL (exp) = gimple_call_tail_p (stmt); @@ -2194,46 +2194,6 @@ round_udiv_adjust (enum machine_mode mode, rtx mod, rtx op1) const1_rtx, const0_rtx); } -/* Wrap modeless constants in CONST:MODE. */ -rtx -wrap_constant (enum machine_mode mode, rtx x) -{ - if (GET_MODE (x) != VOIDmode) - return x; - - if (CONST_INT_P (x) - || GET_CODE (x) == CONST_FIXED - || GET_CODE (x) == CONST_DOUBLE - || GET_CODE (x) == LABEL_REF) - { - gcc_assert (mode != VOIDmode); - - x = gen_rtx_CONST (mode, x); - } - - return x; -} - -/* Remove CONST wrapper added by wrap_constant(). */ -rtx -unwrap_constant (rtx x) -{ - rtx ret = x; - - if (GET_CODE (x) != CONST) - return x; - - x = XEXP (x, 0); - - if (CONST_INT_P (x) - || GET_CODE (x) == CONST_FIXED - || GET_CODE (x) == CONST_DOUBLE - || GET_CODE (x) == LABEL_REF) - ret = x; - - return ret; -} - /* Convert X to MODE, that must be Pmode or ptr_mode, without emitting any rtl. */ @@ -2275,6 +2235,9 @@ expand_debug_expr (tree exp) rtx op0 = NULL_RTX, op1 = NULL_RTX, op2 = NULL_RTX; enum machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp)); + addr_space_t as; + enum machine_mode address_mode; + enum machine_mode pointer_mode; switch (TREE_CODE_CLASS (TREE_CODE (exp))) { @@ -2356,11 +2319,21 @@ expand_debug_expr (tree exp) case COMPLEX_CST: gcc_assert (COMPLEX_MODE_P (mode)); op0 = expand_debug_expr (TREE_REALPART (exp)); - op0 = wrap_constant (GET_MODE_INNER (mode), op0); op1 = expand_debug_expr (TREE_IMAGPART (exp)); - op1 = wrap_constant (GET_MODE_INNER (mode), op1); return gen_rtx_CONCAT (mode, op0, op1); + case DEBUG_EXPR_DECL: + op0 = DECL_RTL_IF_SET (exp); + + if (op0) + return op0; + + op0 = gen_rtx_DEBUG_EXPR (mode); + DEBUG_EXPR_TREE_DECL (op0) = exp; + SET_DECL_RTL (exp, op0); + + return op0; + case VAR_DECL: case PARM_DECL: case FUNCTION_DECL: @@ -2376,7 +2349,8 @@ expand_debug_expr (tree exp) || DECL_EXTERNAL (exp) || !TREE_STATIC (exp) || !DECL_NAME (exp) - || DECL_HARD_REGISTER (exp)) + || DECL_HARD_REGISTER (exp) + || mode == VOIDmode) return NULL; op0 = DECL_RTL (exp); @@ -2458,20 +2432,29 @@ expand_debug_expr (tree exp) if (!op0) return NULL; - gcc_assert (GET_MODE (op0) == Pmode - || GET_MODE (op0) == ptr_mode + if (POINTER_TYPE_P (TREE_TYPE (exp))) + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); + else + as = ADDR_SPACE_GENERIC; + + address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.addr_space.pointer_mode (as); + + gcc_assert (GET_MODE (op0) == address_mode + || GET_MODE (op0) == pointer_mode || GET_CODE (op0) == CONST_INT || GET_CODE (op0) == CONST_DOUBLE); if (TREE_CODE (exp) == ALIGN_INDIRECT_REF) { int align = TYPE_ALIGN_UNIT (TREE_TYPE (exp)); - op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align)); + op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align)); } op0 = gen_rtx_MEM (mode, op0); set_mem_attributes (op0, exp, 0); + set_mem_addr_space (op0, as); return op0; @@ -2485,14 +2468,19 @@ expand_debug_expr (tree exp) if (!op0) return NULL; - gcc_assert (GET_MODE (op0) == Pmode - || GET_MODE (op0) == ptr_mode + as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); + address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.addr_space.pointer_mode (as); + + gcc_assert (GET_MODE (op0) == address_mode + || GET_MODE (op0) == pointer_mode || GET_CODE (op0) == CONST_INT || GET_CODE (op0) == CONST_DOUBLE); op0 = gen_rtx_MEM (mode, op0); set_mem_attributes (op0, exp, 0); + set_mem_addr_space (op0, as); return op0; @@ -2512,6 +2500,9 @@ expand_debug_expr (tree exp) &mode1, &unsignedp, &volatilep, false); rtx orig_op0; + if (bitsize == 0) + return NULL; + orig_op0 = op0 = expand_debug_expr (tem); if (!op0) @@ -2549,6 +2540,9 @@ expand_debug_expr (tree exp) if (MEM_P (op0)) { + if (mode1 == VOIDmode) + /* Bitfield. */ + mode1 = smallest_mode_for_size (bitsize, MODE_INT); if (bitpos >= BITS_PER_UNIT) { op0 = adjust_address_nv (op0, mode1, bitpos / BITS_PER_UNIT); @@ -2556,7 +2550,8 @@ expand_debug_expr (tree exp) } else if (bitpos < 0) { - int units = (-bitpos + BITS_PER_UNIT - 1) / BITS_PER_UNIT; + HOST_WIDE_INT units + = (-bitpos + BITS_PER_UNIT - 1) / BITS_PER_UNIT; op0 = adjust_address_nv (op0, mode1, units); bitpos += units * BITS_PER_UNIT; } @@ -2574,6 +2569,9 @@ expand_debug_expr (tree exp) if (bitpos == 0 && mode == GET_MODE (op0)) return op0; + if (bitpos < 0) + return NULL; + if ((bitpos % BITS_PER_UNIT) == 0 && bitsize == GET_MODE_BITSIZE (mode1)) { @@ -2850,6 +2848,46 @@ expand_debug_expr (tree exp) op1 = gen_rtx_CONST (GET_MODE_INNER (mode), op1); return gen_rtx_CONCAT (mode, op0, op1); + case CONJ_EXPR: + if (GET_CODE (op0) == CONCAT) + return gen_rtx_CONCAT (mode, XEXP (op0, 0), + gen_rtx_NEG (GET_MODE_INNER (mode), + XEXP (op0, 1))); + else + { + enum machine_mode imode = GET_MODE_INNER (mode); + rtx re, im; + + if (MEM_P (op0)) + { + re = adjust_address_nv (op0, imode, 0); + im = adjust_address_nv (op0, imode, GET_MODE_SIZE (imode)); + } + else + { + enum machine_mode ifmode = int_mode_for_mode (mode); + enum machine_mode ihmode = int_mode_for_mode (imode); + rtx halfsize; + if (ifmode == BLKmode || ihmode == BLKmode) + return NULL; + halfsize = GEN_INT (GET_MODE_BITSIZE (ihmode)); + re = op0; + if (mode != ifmode) + re = gen_rtx_SUBREG (ifmode, re, 0); + re = gen_rtx_ZERO_EXTRACT (ihmode, re, halfsize, const0_rtx); + if (imode != ihmode) + re = gen_rtx_SUBREG (imode, re, 0); + im = copy_rtx (op0); + if (mode != ifmode) + im = gen_rtx_SUBREG (ifmode, im, 0); + im = gen_rtx_ZERO_EXTRACT (ihmode, im, halfsize, halfsize); + if (imode != ihmode) + im = gen_rtx_SUBREG (imode, im, 0); + } + im = gen_rtx_NEG (imode, im); + return gen_rtx_CONCAT (mode, re, im); + } + case ADDR_EXPR: op0 = expand_debug_expr (TREE_OPERAND (exp, 0)); if (!op0 || !MEM_P (op0)) @@ -3410,8 +3448,18 @@ expand_stack_alignment (void) || crtl->has_nonlocal_goto) crtl->need_drap = true; - gcc_assert (crtl->stack_alignment_needed - <= crtl->stack_alignment_estimated); + /* Call update_stack_boundary here again to update incoming stack + boundary. It may set incoming stack alignment to a different + value after RTL expansion. TARGET_FUNCTION_OK_FOR_SIBCALL may + use the minimum incoming stack alignment to check if it is OK + to perform sibcall optimization since sibcall optimization will + only align the outgoing stack to incoming stack boundary. */ + if (targetm.calls.update_stack_boundary) + targetm.calls.update_stack_boundary (); + + /* The incoming stack frame has to be aligned at least at + parm_stack_boundary. */ + gcc_assert (crtl->parm_stack_boundary <= INCOMING_STACK_BOUNDARY); /* Update crtl->stack_alignment_estimated and use it later to align stack. We check PREFERRED_STACK_BOUNDARY if there may be non-call @@ -3427,6 +3475,9 @@ expand_stack_alignment (void) if (preferred_stack_boundary > crtl->stack_alignment_needed) crtl->stack_alignment_needed = preferred_stack_boundary; + gcc_assert (crtl->stack_alignment_needed + <= crtl->stack_alignment_estimated); + crtl->stack_realign_needed = INCOMING_STACK_BOUNDARY < crtl->stack_alignment_estimated; crtl->stack_realign_tried = crtl->stack_realign_needed; @@ -3503,7 +3554,7 @@ gimple_expand_cfg (void) targetm.expand_to_rtl_hook (); crtl->stack_alignment_needed = STACK_BOUNDARY; crtl->max_used_stack_slot_alignment = STACK_BOUNDARY; - crtl->stack_alignment_estimated = STACK_BOUNDARY; + crtl->stack_alignment_estimated = 0; crtl->preferred_stack_boundary = STACK_BOUNDARY; cfun->cfg->max_jumptable_ents = 0; @@ -3567,23 +3618,6 @@ gimple_expand_cfg (void) if (crtl->stack_protect_guard) stack_protect_prologue (); - /* Update stack boundary if needed. */ - if (SUPPORTS_STACK_ALIGNMENT) - { - /* Call update_stack_boundary here to update incoming stack - boundary before TARGET_FUNCTION_OK_FOR_SIBCALL is called. - TARGET_FUNCTION_OK_FOR_SIBCALL needs to know the accurate - incoming stack alignment to check if it is OK to perform - sibcall optimization since sibcall optimization will only - align the outgoing stack to incoming stack boundary. */ - if (targetm.calls.update_stack_boundary) - targetm.calls.update_stack_boundary (); - - /* The incoming stack frame has to be aligned at least at - parm_stack_boundary. */ - gcc_assert (crtl->parm_stack_boundary <= INCOMING_STACK_BOUNDARY); - } - expand_phi_nodes (&SA); /* Register rtl specific functions for cfg. */ diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h index d6c26bf0ba0..4abdf8bfe15 100644 --- a/gcc/cfgloop.h +++ b/gcc/cfgloop.h @@ -288,6 +288,7 @@ extern edge create_empty_if_region_on_edge (edge, tree); extern struct loop *create_empty_loop_on_edge (edge, tree, tree, tree, tree, tree *, tree *, struct loop *); extern struct loop * duplicate_loop (struct loop *, struct loop *); +extern void duplicate_subloops (struct loop *, struct loop *); extern bool duplicate_loop_to_header_edge (struct loop *, edge, unsigned, sbitmap, edge, VEC (edge, heap) **, int); diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c index a357a2fd77a..6f24415a72d 100644 --- a/gcc/cfgloopmanip.c +++ b/gcc/cfgloopmanip.c @@ -32,7 +32,6 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "tree-flow.h" -static void duplicate_subloops (struct loop *, struct loop *); static void copy_loops_to (struct loop **, int, struct loop *); static void loop_redirect_edge (edge, basic_block); @@ -886,7 +885,7 @@ duplicate_loop (struct loop *loop, struct loop *target) /* Copies structure of subloops of LOOP into TARGET loop, placing newly created loops into loop tree. */ -static void +void duplicate_subloops (struct loop *loop, struct loop *target) { struct loop *aloop, *cloop; diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 15dd60a7ee4..167e8a8e7b4 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -802,7 +802,7 @@ initialize_inline_failed (struct cgraph_edge *e) e->inline_failed = CIF_REDEFINED_EXTERN_INLINE; else if (!callee->local.inlinable) e->inline_failed = CIF_FUNCTION_NOT_INLINABLE; - else if (gimple_call_cannot_inline_p (e->call_stmt)) + else if (e->call_stmt && gimple_call_cannot_inline_p (e->call_stmt)) e->inline_failed = CIF_MISMATCHED_ARGUMENTS; else e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED; @@ -816,13 +816,19 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, { struct cgraph_edge *edge; + + /* LTO does not actually have access to the call_stmt since these + have not been loaded yet. */ + if (call_stmt) + { #ifdef ENABLE_CHECKING - /* This is rather pricely check possibly trigerring construction of call stmt - hashtable. */ - gcc_assert (!cgraph_edge (caller, call_stmt)); + /* This is rather pricely check possibly trigerring construction of + call stmt hashtable. */ + gcc_assert (!cgraph_edge (caller, call_stmt)); #endif - gcc_assert (is_gimple_call (call_stmt)); + gcc_assert (is_gimple_call (call_stmt)); + } if (free_edges) { @@ -841,7 +847,8 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, edge->callee = callee; edge->call_stmt = call_stmt; push_cfun (DECL_STRUCT_FUNCTION (caller->decl)); - edge->can_throw_external = stmt_can_throw_external (call_stmt); + edge->can_throw_external + = call_stmt ? stmt_can_throw_external (call_stmt) : false; pop_cfun (); edge->prev_caller = NULL; edge->next_caller = callee->callers; @@ -860,7 +867,9 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee, gcc_assert (freq <= CGRAPH_FREQ_MAX); edge->loop_nest = nest; edge->indirect_call = 0; - if (caller->call_site_hash) + edge->call_stmt_cannot_inline_p = + (call_stmt ? gimple_call_cannot_inline_p (call_stmt) : false); + if (call_stmt && caller->call_site_hash) { void **slot; slot = htab_find_slot_with_hash (caller->call_site_hash, @@ -1351,6 +1360,7 @@ void cgraph_mark_needed_node (struct cgraph_node *node) { node->needed = 1; + gcc_assert (!node->global.inlined_to); cgraph_mark_reachable_node (node); } @@ -1624,8 +1634,8 @@ cgraph_function_possibly_inlined_p (tree decl) /* Create clone of E in the node N represented by CALL_EXPR the callgraph. */ struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, - gimple call_stmt, gcov_type count_scale, int freq_scale, - int loop_nest, bool update_original) + gimple call_stmt, unsigned stmt_uid, gcov_type count_scale, + int freq_scale, int loop_nest, bool update_original) { struct cgraph_edge *new_edge; gcov_type count = e->count * count_scale / REG_BR_PROB_BASE; @@ -1638,6 +1648,7 @@ cgraph_clone_edge (struct cgraph_edge *e, struct cgraph_node *n, new_edge->inline_failed = e->inline_failed; new_edge->indirect_call = e->indirect_call; + new_edge->lto_stmt_uid = stmt_uid; if (update_original) { e->count -= new_edge->count; @@ -1673,6 +1684,7 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq, } new_node->analyzed = n->analyzed; new_node->local = n->local; + new_node->local.externally_visible = false; new_node->global = n->global; new_node->rtl = n->rtl; new_node->count = count; @@ -1702,8 +1714,8 @@ cgraph_clone_node (struct cgraph_node *n, gcov_type count, int freq, for (e = n->callees;e; e=e->next_callee) - cgraph_clone_edge (e, new_node, e->call_stmt, count_scale, freq, loop_nest, - update_original); + cgraph_clone_edge (e, new_node, e->call_stmt, e->lto_stmt_uid, + count_scale, freq, loop_nest, update_original); new_node->next_sibling_clone = n->clones; if (n->clones) @@ -1972,7 +1984,8 @@ cgraph_add_new_function (tree fndecl, bool lowered) bool cgraph_node_can_be_local_p (struct cgraph_node *node) { - return !node->needed; + return (!node->needed + && (DECL_COMDAT (node->decl) || !node->local.externally_visible)); } /* Bring NODE local. */ diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 292eccd0284..016ce9de14c 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -46,6 +46,10 @@ enum availability AVAIL_LOCAL }; +/* This is the information that is put into the cgraph local structure + to recover a function. */ +struct lto_file_decl_data; + extern const char * const cgraph_availability_names[]; /* Function inlining information. */ @@ -69,6 +73,9 @@ struct GTY(()) inline_summary Available after function is analyzed. */ struct GTY(()) cgraph_local_info { + /* File stream where this node is being written to. */ + struct lto_file_decl_data * GTY ((skip)) lto_file_data; + struct inline_summary inline_summary; /* Set when function function is visible in current compilation unit only @@ -277,6 +284,9 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgrap struct cgraph_edge *prev_callee; struct cgraph_edge *next_callee; gimple call_stmt; + /* The stmt_uid of this call stmt. This is used by LTO to recover + the call_stmt when the function is serialized in. */ + unsigned int lto_stmt_uid; PTR GTY ((skip (""))) aux; /* When equal to CIF_OK, inline this call. Otherwise, points to the explanation why function was not inlined. */ @@ -291,6 +301,8 @@ struct GTY((chain_next ("%h.next_caller"), chain_prev ("%h.prev_caller"))) cgrap unsigned int loop_nest : 30; /* Whether this edge describes a call that was originally indirect. */ unsigned int indirect_call : 1; + /* True if the corresponding CALL stmt cannot be inlined. */ + unsigned int call_stmt_cannot_inline_p : 1; /* Can this call throw externally? */ unsigned int can_throw_external : 1; /* Unique id of the edge. */ @@ -406,8 +418,8 @@ struct cgraph_global_info *cgraph_global_info (tree); struct cgraph_rtl_info *cgraph_rtl_info (tree); const char * cgraph_node_name (struct cgraph_node *); struct cgraph_edge * cgraph_clone_edge (struct cgraph_edge *, - struct cgraph_node *, - gimple, gcov_type, int, int, bool); + struct cgraph_node *, gimple, + unsigned, gcov_type, int, int, bool); struct cgraph_node * cgraph_clone_node (struct cgraph_node *, gcov_type, int, int, bool, VEC(cgraph_edge_p,heap) *); @@ -430,6 +442,7 @@ struct cgraph_node * cgraph_create_virtual_clone (struct cgraph_node *old_node, void cgraph_finalize_function (tree, bool); void cgraph_mark_if_needed (tree); void cgraph_finalize_compilation_unit (void); +void cgraph_optimize (void); void cgraph_mark_needed_node (struct cgraph_node *); void cgraph_mark_address_taken_node (struct cgraph_node *); void cgraph_mark_reachable_node (struct cgraph_node *); @@ -446,9 +459,11 @@ struct cgraph_node *cgraph_function_versioning (struct cgraph_node *, bitmap); void tree_function_versioning (tree, tree, VEC (ipa_replace_map_p,gc)*, bool, bitmap); struct cgraph_node *save_inline_function_body (struct cgraph_node *); -void record_references_in_initializer (tree); +void record_references_in_initializer (tree, bool); bool cgraph_process_new_functions (void); +bool cgraph_decide_is_function_needed (struct cgraph_node *, tree); + typedef void (*cgraph_edge_hook)(struct cgraph_edge *, void *); typedef void (*cgraph_node_hook)(struct cgraph_node *, void *); typedef void (*cgraph_2edge_hook)(struct cgraph_edge *, struct cgraph_edge *, @@ -476,6 +491,7 @@ void cgraph_materialize_all_clones (void); /* In cgraphbuild.c */ unsigned int rebuild_cgraph_edges (void); +void reset_inline_failed (struct cgraph_node *); int compute_call_stmt_bb_frequency (tree, basic_block bb); /* In ipa.c */ @@ -560,6 +576,22 @@ unsigned int compute_inline_parameters (struct cgraph_node *); /* Create a new static variable of type TYPE. */ tree add_new_static_var (tree type); +/* lto-cgraph.c */ + +enum LTO_cgraph_tags +{ + /* Must leave 0 for the stopper. */ + LTO_cgraph_avail_node = 1, + LTO_cgraph_overwritable_node, + LTO_cgraph_unavail_node, + LTO_cgraph_edge, + LTO_cgraph_last_tag +}; + +extern const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag]; + +#define LCC_NOT_FOUND (-1) + /* Return true if iterator CSI points to nothing. */ static inline bool @@ -626,6 +658,26 @@ struct GTY(()) constant_descriptor_tree { hashval_t hash; }; +/* Return true when function NODE is only called directly. + i.e. it is not externally visible, address was not taken and + it is not used in any other non-standard way. */ + +static inline bool +cgraph_only_called_directly_p (struct cgraph_node *node) +{ + return !node->needed && !node->local.externally_visible; +} + +/* Return true when function NODE can be removed from callgraph + if all direct calls are eliminated. */ + +static inline bool +cgraph_can_remove_if_no_direct_calls_p (struct cgraph_node *node) +{ + return (!node->needed + && (DECL_COMDAT (node->decl) || !node->local.externally_visible)); +} + /* Constant pool accessor function. */ htab_t constant_pool_htab (void); diff --git a/gcc/cgraphbuild.c b/gcc/cgraphbuild.c index a7a8bd2b314..65e3d67e14c 100644 --- a/gcc/cgraphbuild.c +++ b/gcc/cgraphbuild.c @@ -33,13 +33,16 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" /* Walk tree and record all calls and references to functions/variables. - Called via walk_tree: TP is pointer to tree to be examined. */ + Called via walk_tree: TP is pointer to tree to be examined. + When DATA is non-null, record references to callgraph. + */ static tree -record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +record_reference (tree *tp, int *walk_subtrees, void *data) { tree t = *tp; tree decl; + bool do_callgraph = data != NULL; switch (TREE_CODE (t)) { @@ -57,7 +60,7 @@ record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) /* Record dereferences to the functions. This makes the functions reachable unconditionally. */ decl = TREE_OPERAND (*tp, 0); - if (TREE_CODE (decl) == FUNCTION_DECL) + if (TREE_CODE (decl) == FUNCTION_DECL && do_callgraph) cgraph_mark_address_taken_node (cgraph_node (decl)); break; @@ -78,6 +81,29 @@ record_reference (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) return NULL_TREE; } +/* Reset inlining information of all incoming call edges of NODE. */ + +void +reset_inline_failed (struct cgraph_node *node) +{ + struct cgraph_edge *e; + + for (e = node->callers; e; e = e->next_caller) + { + e->callee->global.inlined_to = NULL; + if (!node->analyzed) + e->inline_failed = CIF_BODY_NOT_AVAILABLE; + else if (node->local.redefined_extern_inline) + e->inline_failed = CIF_REDEFINED_EXTERN_INLINE; + else if (!node->local.inlinable) + e->inline_failed = CIF_FUNCTION_NOT_INLINABLE; + else if (e->call_stmt_cannot_inline_p) + e->inline_failed = CIF_MISMATCHED_ARGUMENTS; + else + e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED; + } +} + /* Computes the frequency of the call statement so that it can be stored in cgraph_edge. BB is the basic block of the call statement. */ int @@ -195,13 +221,15 @@ struct gimple_opt_pass pass_build_cgraph_edges = }; /* Record references to functions and other variables present in the - initial value of DECL, a variable. */ + initial value of DECL, a variable. + When ONLY_VARS is true, we mark needed only variables, not functions. */ void -record_references_in_initializer (tree decl) +record_references_in_initializer (tree decl, bool only_vars) { struct pointer_set_t *visited_nodes = pointer_set_create (); - walk_tree (&DECL_INITIAL (decl), record_reference, NULL, visited_nodes); + walk_tree (&DECL_INITIAL (decl), record_reference, + only_vars ? NULL : decl, visited_nodes); pointer_set_destroy (visited_nodes); } diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 2ad07187e04..7105e59c5ec 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -140,7 +140,6 @@ static void cgraph_expand_all_functions (void); static void cgraph_mark_functions_to_output (void); static void cgraph_expand_function (struct cgraph_node *); static void cgraph_output_pending_asms (void); -static void cgraph_optimize (void); static void cgraph_analyze_function (struct cgraph_node *); static FILE *cgraph_dump_file; @@ -314,16 +313,9 @@ cgraph_build_cdtor_fns (void) either outside this translation unit, something magic in the system configury. */ -static bool -decide_is_function_needed (struct cgraph_node *node, tree decl) +bool +cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl) { - if (MAIN_NAME_P (DECL_NAME (decl)) - && TREE_PUBLIC (decl)) - { - node->local.externally_visible = true; - return true; - } - /* If the user told us it is used, then it must be so. */ if (node->local.externally_visible) return true; @@ -361,7 +353,9 @@ decide_is_function_needed (struct cgraph_node *node, tree decl) || (!optimize && !node->local.disregard_inline_limits && !DECL_DECLARED_INLINE_P (decl) && !node->origin)) - && !flag_whole_program) + && !flag_whole_program + && !flag_lto + && !flag_whopr) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl)) return true; @@ -522,7 +516,7 @@ cgraph_finalize_function (tree decl, bool nested) node->finalized_by_frontend = true; record_cdtor_fn (node->decl); - if (decide_is_function_needed (node, decl)) + if (cgraph_decide_is_function_needed (node, decl)) cgraph_mark_needed_node (node); /* Since we reclaim unreachable nodes at the end of every language @@ -551,7 +545,7 @@ void cgraph_mark_if_needed (tree decl) { struct cgraph_node *node = cgraph_node (decl); - if (node->local.finalized && decide_is_function_needed (node, decl)) + if (node->local.finalized && cgraph_decide_is_function_needed (node, decl)) cgraph_mark_needed_node (node); } @@ -594,6 +588,21 @@ verify_cgraph_node (struct cgraph_node *node) error ("Execution count is negative"); error_found = true; } + if (node->global.inlined_to && node->local.externally_visible) + { + error ("Externally visible inline clone"); + error_found = true; + } + if (node->global.inlined_to && node->address_taken) + { + error ("Inline clone with address taken"); + error_found = true; + } + if (node->global.inlined_to && node->needed) + { + error ("Inline clone is needed"); + error_found = true; + } for (e = node->callers; e; e = e->next_caller) { if (e->count < 0) @@ -692,7 +701,8 @@ verify_cgraph_node (struct cgraph_node *node) if (node->analyzed && gimple_has_body_p (node->decl) && !TREE_ASM_WRITTEN (node->decl) - && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to)) + && (!DECL_EXTERNAL (node->decl) || node->global.inlined_to) + && !flag_wpa) { if (this_cfun->cfg) { @@ -864,12 +874,8 @@ process_function_and_variable_attributes (struct cgraph_node *first, warning_at (DECL_SOURCE_LOCATION (node->decl), OPT_Wattributes, "%" " attribute have effect only on public objects"); - else - { - if (node->local.finalized) - cgraph_mark_needed_node (node); - node->local.externally_visible = true; - } + else if (node->local.finalized) + cgraph_mark_needed_node (node); } } for (vnode = varpool_nodes; vnode != first_var; vnode = vnode->next) @@ -887,12 +893,8 @@ process_function_and_variable_attributes (struct cgraph_node *first, warning_at (DECL_SOURCE_LOCATION (vnode->decl), OPT_Wattributes, "%" " attribute have effect only on public objects"); - else - { - if (vnode->finalized) - varpool_mark_needed_node (vnode); - vnode->externally_visible = true; - } + else if (vnode->finalized) + varpool_mark_needed_node (vnode); } } } @@ -949,8 +951,8 @@ cgraph_analyze_functions (void) continue; } - gcc_assert (!node->analyzed && node->reachable); - cgraph_analyze_function (node); + if (!node->analyzed) + cgraph_analyze_function (node); for (edge = node->callees; edge; edge = edge->next_callee) if (!edge->callee->reachable) @@ -1355,15 +1357,34 @@ ipa_passes (void) current_function_decl = NULL; gimple_register_cfg_hooks (); bitmap_obstack_initialize (NULL); - execute_ipa_pass_list (all_ipa_passes); - /* Generate coverage variables and constructors. */ - coverage_finish (); + if (!in_lto_p) + execute_ipa_pass_list (all_small_ipa_passes); - /* Process new functions added. */ - set_cfun (NULL); - current_function_decl = NULL; - cgraph_process_new_functions (); + /* If pass_all_early_optimizations was not scheduled, the state of + the cgraph will not be properly updated. Update it now. */ + if (cgraph_state < CGRAPH_STATE_IPA_SSA) + cgraph_state = CGRAPH_STATE_IPA_SSA; + + if (!in_lto_p) + { + /* Generate coverage variables and constructors. */ + coverage_finish (); + + /* Process new functions added. */ + set_cfun (NULL); + current_function_decl = NULL; + cgraph_process_new_functions (); + + execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_regular_ipa_passes); + } + execute_ipa_summary_passes ((struct ipa_opt_pass_d *) all_lto_gen_passes); + + if (!in_lto_p) + ipa_write_summaries (); + + if (!flag_ltrans) + execute_ipa_pass_list (all_regular_ipa_passes); bitmap_obstack_release (NULL); } @@ -1371,7 +1392,7 @@ ipa_passes (void) /* Perform simple optimizations based on callgraph. */ -static void +void cgraph_optimize (void) { if (errorcount || sorrycount) @@ -1401,7 +1422,10 @@ cgraph_optimize (void) /* Do nothing else if any IPA pass found errors. */ if (errorcount || sorrycount) - return; + { + timevar_pop (TV_CGRAPHOPT); + return; + } /* This pass remove bodies of extern inline functions we never inlined. Do this later so other IPA passes see what is really going on. */ @@ -1421,6 +1445,7 @@ cgraph_optimize (void) timevar_pop (TV_CGRAPHOPT); /* Output everything. */ + (*debug_hooks->assembly_start) (); if (!quiet_flag) fprintf (stderr, "Assembling functions:\n"); #ifdef ENABLE_CHECKING @@ -1598,7 +1623,8 @@ cgraph_copy_node_for_versioning (struct cgraph_node *old_version, also cloned. */ for (e = old_version->callees;e; e=e->next_callee) { - new_e = cgraph_clone_edge (e, new_version, e->call_stmt, 0, e->frequency, + new_e = cgraph_clone_edge (e, new_version, e->call_stmt, + e->lto_stmt_uid, 0, e->frequency, e->loop_nest, true); new_e->count = e->count; } diff --git a/gcc/collect2.c b/gcc/collect2.c index 82c400bbaaf..03300f3c79b 100644 --- a/gcc/collect2.c +++ b/gcc/collect2.c @@ -184,6 +184,15 @@ static int aix64_flag; /* true if -b64 */ static int aixrtl_flag; /* true if -brtl */ #endif +enum lto_mode_d { + LTO_MODE_NONE, /* Not doing LTO. */ + LTO_MODE_LTO, /* Normal LTO. */ + LTO_MODE_WHOPR /* WHOPR. */ +}; + +/* Current LTO mode. */ +static enum lto_mode_d lto_mode = LTO_MODE_NONE; + int debug; /* true if -debug */ static int shared_obj; /* true if -shared */ @@ -193,6 +202,7 @@ static const char *o_file; /* .o for constructor/destructor list. */ #ifdef COLLECT_EXPORT_LIST static const char *export_file; /* .x for AIX export list. */ #endif +static char **lto_o_files; /* Output files for LTO. */ const char *ldout; /* File for ld stdout. */ const char *lderrout; /* File for ld stderr. */ static const char *output_file; /* Output file for ld. */ @@ -250,6 +260,25 @@ static struct path_prefix *libpaths[3] = {&cmdline_lib_dirs, &libpath_lib_dirs, NULL}; #endif +/* List of names of object files containing LTO information. + These are a subset of the object file names appearing on the + command line, and must be identical, in the sense of pointer + equality, with the names passed to maybe_run_lto_and_relink(). */ + +struct lto_object +{ + const char *name; /* Name of object file. */ + struct lto_object *next; /* Next in linked list. */ +}; + +struct lto_object_list +{ + struct lto_object *first; /* First list element. */ + struct lto_object *last; /* Last list element. */ +}; + +static struct lto_object_list lto_objects; + /* Special kinds of symbols that a name may denote. */ typedef enum { @@ -272,6 +301,7 @@ static void prefix_from_string (const char *, struct path_prefix *); static void do_wait (const char *, struct pex_obj *); static void fork_execute (const char *, char **); static void maybe_unlink (const char *); +static void maybe_unlink_list (char **); static void add_to_list (struct head *, const char *); static int extract_init_priority (const char *); static void sort_ids (struct head *); @@ -310,7 +340,8 @@ typedef enum { PASS_FIRST, /* without constructors */ PASS_OBJ, /* individual objects */ PASS_LIB, /* looking for shared libraries */ - PASS_SECOND /* with constructors linked in */ + PASS_SECOND, /* with constructors linked in */ + PASS_LTOINFO /* looking for objects with LTO info */ } scanpass; /* ... and which kinds of symbols are to be considered. */ @@ -363,6 +394,9 @@ collect_exit (int status) maybe_unlink (export_file); #endif + if (lto_o_files) + maybe_unlink_list (lto_o_files); + if (ldout != 0 && ldout[0]) { dump_file (ldout, stdout); @@ -472,6 +506,9 @@ handler (int signo) maybe_unlink (export_file); #endif + if (lto_o_files) + maybe_unlink_list (lto_o_files); + if (response_file) maybe_unlink (response_file); @@ -815,6 +852,247 @@ prefix_from_string (const char *p, struct path_prefix *pprefix) } free (nstore); } + +#ifdef OBJECT_FORMAT_NONE + +/* Add an entry for the object file NAME to object file list LIST. + New entries are added at the end of the list. The original pointer + value of NAME is preserved, i.e., no string copy is performed. */ + +static void +add_lto_object (struct lto_object_list *list, const char *name) +{ + struct lto_object *n = XNEW (struct lto_object); + n->name = name; + n->next = NULL; + + if (list->last) + list->last->next = n; + else + list->first = n; + + list->last = n; +} +#endif /* OBJECT_FORMAT_NONE */ + + +/* Perform a link-time recompilation and relink if any of the object + files contain LTO info. The linker command line LTO_LD_ARGV + represents the linker command that would produce a final executable + without the use of LTO. OBJECT_LST is a vector of object file names + appearing in LTO_LD_ARGV that are to be considerd for link-time + recompilation, where OBJECT is a pointer to the last valid element. + (This awkward convention avoids an impedance mismatch with the + usage of similarly-named variables in main().) The elements of + OBJECT_LST must be identical, i.e., pointer equal, to the + corresponding arguments in LTO_LD_ARGV. + + Upon entry, at least one linker run has been performed without the + use of any LTO info that might be present. Any recompilations + necessary for template instantiations have been performed, and + initializer/finalizer tables have been created if needed and + included in the linker command line LTO_LD_ARGV. If any of the + object files contain LTO info, we run the LTO back end on all such + files, and perform the final link with the LTO back end output + substituted for the LTO-optimized files. In some cases, a final + link with all link-time generated code has already been performed, + so there is no need to relink if no LTO info is found. In other + cases, our caller has not produced the final executable, and is + relying on us to perform the required link whether LTO info is + present or not. In that case, the FORCE argument should be true. + Note that the linker command line argument LTO_LD_ARGV passed into + this function may be modified in place. */ + +static void +maybe_run_lto_and_relink (char **lto_ld_argv, char **object_lst, + const char **object, bool force) +{ + const char **object_file = CONST_CAST2 (const char **, char **, object_lst); + + int num_lto_c_args = 1; /* Allow space for the terminating NULL. */ + + while (object_file < object) + { + /* If file contains LTO info, add it to the list of LTO objects. */ + scan_prog_file (*object_file++, PASS_LTOINFO, SCAN_ALL); + + /* Increment the argument count by the number of object file arguments + we will add. An upper bound suffices, so just count all of the + object files regardless of whether they contain LTO info. */ + num_lto_c_args++; + } + + if (lto_objects.first) + { + const char *opts; + char **lto_c_argv; + const char **lto_c_ptr; + const char *cp; + const char **p, **q, **r; + const char **lto_o_ptr; + struct lto_object *list; + char *lto_wrapper = getenv ("COLLECT_LTO_WRAPPER"); + struct pex_obj *pex; + const char *prog = "lto-wrapper"; + + if (!lto_wrapper) + fatal ("COLLECT_LTO_WRAPPER must be set."); + + /* There is at least one object file containing LTO info, + so we need to run the LTO back end and relink. */ + + /* Get compiler options passed down from the parent `gcc' command. + These must be passed to the LTO back end. */ + opts = getenv ("COLLECT_GCC_OPTIONS"); + + /* Increment the argument count by the number of inherited options. + Some arguments may be filtered out later. Again, an upper bound + suffices. */ + + cp = opts; + + while (cp && *cp) + { + extract_string (&cp); + num_lto_c_args++; + } + obstack_free (&temporary_obstack, temporary_firstobj); + + if (debug) + num_lto_c_args++; + + /* Increment the argument count by the number of initial + arguments added below. */ + num_lto_c_args += 9; + + lto_c_argv = (char **) xcalloc (sizeof (char *), num_lto_c_args); + lto_c_ptr = CONST_CAST2 (const char **, char **, lto_c_argv); + + *lto_c_ptr++ = lto_wrapper; + *lto_c_ptr++ = c_file_name; + + cp = opts; + + while (cp && *cp) + { + const char *s = extract_string (&cp); + + /* Pass the option or argument to the wrapper. */ + *lto_c_ptr++ = xstrdup (s); + } + obstack_free (&temporary_obstack, temporary_firstobj); + + if (debug) + *lto_c_ptr++ = xstrdup ("-debug"); + + /* Add LTO objects to the wrapper command line. */ + for (list = lto_objects.first; list; list = list->next) + *lto_c_ptr++ = list->name; + + *lto_c_ptr = NULL; + + /* Save intermediate WPA files in lto1 if debug. */ + if (debug) + putenv (xstrdup ("WPA_SAVE_LTRANS=1")); + + /* Run the LTO back end. */ + pex = collect_execute (prog, lto_c_argv, NULL, NULL, PEX_SEARCH); + { + int c; + FILE *stream; + size_t i, num_files; + char *start, *end; + + stream = pex_read_output (pex, 0); + gcc_assert (stream); + + num_files = 0; + while ((c = getc (stream)) != EOF) + { + obstack_1grow (&temporary_obstack, c); + if (c == '\n') + ++num_files; + } + + lto_o_files = XNEWVEC (char *, num_files + 1); + lto_o_files[num_files] = NULL; + start = XOBFINISH (&temporary_obstack, char *); + for (i = 0; i < num_files; ++i) + { + end = start; + while (*end != '\n') + ++end; + *end = '\0'; + + lto_o_files[i] = xstrdup (start); + + start = end + 1; + } + + obstack_free (&temporary_obstack, temporary_firstobj); + } + do_wait (prog, pex); + pex = NULL; + + /* After running the LTO back end, we will relink, substituting + the LTO output for the object files that we submitted to the + LTO. Here, we modify the linker command line for the relink. */ + p = CONST_CAST2 (const char **, char **, lto_ld_argv); + lto_o_ptr = CONST_CAST2 (const char **, char **, lto_o_files); + + while (*p != NULL) + { + for (list = lto_objects.first; list; list = list->next) + { + if (*p == list->name) /* Note test for pointer equality! */ + { + /* Excise argument from linker command line. */ + if (*lto_o_ptr) + { + /* Replace first argument with LTO output file. */ + *p++ = *lto_o_ptr++; + } + else + { + /* Move following arguments one position earlier, + overwriting the current argument. */ + q = p; + r = p + 1; + while (*r != NULL) + *q++ = *r++; + *q = NULL; + } + + /* No need to continue searching the LTO object list. */ + break; + } + } + + /* If we didn't find a match, move on to the next argument. + Otherwise, P has been set to the correct argument position + at which to continue. */ + if (!list) ++p; + } + + /* The code above assumes we will never have more lto output files than + input files. Otherwise, we need to resize lto_ld_argv. Check this + assumption. */ + if (*lto_o_ptr) + fatal ("too many lto output files"); + + /* Run the linker again, this time replacing the object files + optimized by the LTO with the temporary file generated by the LTO. */ + fork_execute ("ld", lto_ld_argv); + + maybe_unlink_list (lto_o_files); + } + else if (force) + { + /* Our caller is relying on us to do the link + even though there is no LTO back end work to be done. */ + fork_execute ("ld", lto_ld_argv); + } +} /* Main program. */ @@ -935,14 +1213,25 @@ main (int argc, char **argv) /* Parse command line early for instances of -debug. This allows the debug flag to be set before functions like find_a_file() - are called. */ + are called. We also look for the -flto or -fwhopr flag to know + what LTO mode we are in. */ { int i; + bool use_plugin = false; for (i = 1; argv[i] != NULL; i ++) { if (! strcmp (argv[i], "-debug")) debug = 1; + else if (! strcmp (argv[i], "-flto") && ! use_plugin) + lto_mode = LTO_MODE_LTO; + else if (! strcmp (argv[i], "-fwhopr") && ! use_plugin) + lto_mode = LTO_MODE_WHOPR; + else if (! strcmp (argv[i], "-plugin")) + { + use_plugin = true; + lto_mode = LTO_MODE_NONE; + } #ifdef COLLECT_EXPORT_LIST /* since -brtl, -bexport, -b64 are not position dependent also check for them here */ @@ -985,8 +1274,8 @@ main (int argc, char **argv) obstack_free (&temporary_obstack, temporary_firstobj); /* -fno-profile-arcs -fno-test-coverage -fno-branch-probabilities - -fno-exceptions -w */ - num_c_args += 5; + -fno-exceptions -w -fno-whole-program */ + num_c_args += 6; c_argv = XCNEWVEC (char *, num_c_args); c_ptr = CONST_CAST2 (const char **, char **, c_argv); @@ -1154,6 +1443,7 @@ main (int argc, char **argv) *c_ptr++ = "-fno-branch-probabilities"; *c_ptr++ = "-fno-exceptions"; *c_ptr++ = "-w"; + *c_ptr++ = "-fno-whole-program"; /* !!! When GCC calls collect2, it does not know whether it is calling collect2 or ld. @@ -1194,6 +1484,20 @@ main (int argc, char **argv) } break; + case 'f': + if (strcmp (arg, "-flto") == 0 || strcmp (arg, "-fwhopr") == 0) + { +#ifdef ENABLE_LTO + /* Do not pass LTO flag to the linker. */ + ld1--; + ld2--; +#else + error ("LTO support has not been enabled in this " + "configuration"); +#endif + } + break; + case 'l': if (first_file) { @@ -1456,6 +1760,9 @@ main (int argc, char **argv) if (export_file != 0 && export_file[0]) maybe_unlink (export_file); #endif + if (lto_mode) + maybe_run_lto_and_relink (ld1_argv, object_lst, object, false); + maybe_unlink (c_file); maybe_unlink (o_file); return 0; @@ -1498,6 +1805,9 @@ main (int argc, char **argv) if (ld1_filter == SCAN_NOTHING) do_tlink (ld1_argv, object_lst); + if (lto_mode) + maybe_run_lto_and_relink (ld1_argv, object_lst, object, false); + /* Strip now if it was requested on the command line. */ if (strip_flag) { @@ -1591,9 +1901,15 @@ main (int argc, char **argv) #ifdef COLLECT_EXPORT_LIST /* On AIX we must call tlink because of possible templates resolution. */ do_tlink (ld2_argv, object_lst); + + if (lto_mode) + maybe_run_lto_and_relink (ld2_argv, object_lst, object, false); #else /* Otherwise, simply call ld because tlink is already done. */ - fork_execute ("ld", ld2_argv); + if (lto_mode) + maybe_run_lto_and_relink (ld2_argv, object_lst, object, true); + else + fork_execute ("ld", ld2_argv); /* Let scan_prog_file do any final mods (OSF/rose needs this for constructors/destructors in shared libraries. */ @@ -1661,7 +1977,7 @@ do_wait (const char *prog, struct pex_obj *pex) struct pex_obj * collect_execute (const char *prog, char **argv, const char *outname, - const char *errname) + const char *errname, int flags) { struct pex_obj *pex; const char *errmsg; @@ -1737,7 +2053,7 @@ collect_execute (const char *prog, char **argv, const char *outname, if (pex == NULL) fatal_perror ("pex_init failed"); - errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, outname, + errmsg = pex_run (pex, flags, argv[0], argv, outname, errname, &err); if (errmsg != NULL) { @@ -1761,7 +2077,7 @@ fork_execute (const char *prog, char **argv) { struct pex_obj *pex; - pex = collect_execute (prog, argv, NULL, NULL); + pex = collect_execute (prog, argv, NULL, NULL, PEX_LAST | PEX_SEARCH); do_wait (prog, pex); } @@ -1776,6 +2092,17 @@ maybe_unlink (const char *file) notice ("[Leaving %s]\n", file); } +/* Call maybe_unlink on the NULL-terminated list, FILE_LIST. */ + +static void +maybe_unlink_list (char **file_list) +{ + char **tmp = file_list; + + while (*tmp) + maybe_unlink (*(tmp++)); +} + static long sequence_number = 0; @@ -2170,6 +2497,25 @@ write_aix_file (FILE *stream, struct id *list) #ifdef OBJECT_FORMAT_NONE +/* Check to make sure the file is an ELF file. LTO objects must + be in ELF format. */ + +static bool +is_elf (const char *prog_name) +{ + FILE *f; + char buf[4]; + static char magic[4] = { 0x7f, 'E', 'L', 'F' }; + + f = fopen (prog_name, "r"); + if (f == NULL) + return false; + if (fread (buf, sizeof (buf), 1, f) != 1) + buf[0] = 0; + fclose (f); + return memcmp (buf, magic, sizeof (magic)) == 0; +} + /* Generic version to scan the name list of the loaded program for the symbols g++ uses for static constructors and destructors. */ @@ -2189,10 +2535,17 @@ scan_prog_file (const char *prog_name, scanpass which_pass, int err; char *p, buf[1024]; FILE *inf; + int found_lto = 0; if (which_pass == PASS_SECOND) return; + /* LTO objects must be in ELF format. This check prevents + us from accepting an archive containing LTO objects, which + gcc cannnot currently handle. */ + if (which_pass == PASS_LTOINFO && !is_elf (prog_name)) + return; + /* If we do not have an `nm', complain. */ if (nm_file_name == 0) fatal ("cannot find 'nm'"); @@ -2223,7 +2576,8 @@ scan_prog_file (const char *prog_name, scanpass which_pass, if (pex == NULL) fatal_perror ("pex_init failed"); - errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, NULL, &err); + errmsg = pex_run (pex, 0, nm_file_name, real_nm_argv, NULL, HOST_BIT_BUCKET, + &err); if (errmsg != NULL) { if (err != 0) @@ -2245,7 +2599,12 @@ scan_prog_file (const char *prog_name, scanpass which_pass, fatal_perror ("can't open nm output"); if (debug) - fprintf (stderr, "\nnm output with constructors/destructors.\n"); + { + if (which_pass == PASS_LTOINFO) + fprintf (stderr, "\nnm output with LTO info marker symbol.\n"); + else + fprintf (stderr, "\nnm output with constructors/destructors.\n"); + } /* Read each line of nm output. */ while (fgets (buf, sizeof buf, inf) != (char *) 0) @@ -2253,6 +2612,33 @@ scan_prog_file (const char *prog_name, scanpass which_pass, int ch, ch2; char *name, *end; + if (debug) + fprintf (stderr, "\t%s\n", buf); + + if (which_pass == PASS_LTOINFO) + { + if (found_lto) + continue; + + /* Look for the LTO info marker symbol, and add filename to + the LTO objects list if found. */ + for (p = buf; (ch = *p) != '\0' && ch != '\n'; p++) + if (ch == ' ' + && (strncmp (p +1 , "gnu_lto_v1", 10) == 0) + && ISSPACE( p[11])) + { + add_lto_object (<o_objects, prog_name); + + /* We need to read all the input, so we can't just + return here. But we can avoid useless work. */ + found_lto = 1; + + break; + } + + continue; + } + /* If it contains a constructor or destructor name, add the name to the appropriate list unless this is a kind of symbol we're not supposed to even consider. */ @@ -2319,9 +2705,6 @@ scan_prog_file (const char *prog_name, scanpass which_pass, default: /* not a constructor or destructor */ continue; } - - if (debug) - fprintf (stderr, "\t%s\n", buf); } if (debug) diff --git a/gcc/collect2.h b/gcc/collect2.h index 3990b4ffec6..81113cfb68b 100644 --- a/gcc/collect2.h +++ b/gcc/collect2.h @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3. If not see extern void do_tlink (char **, char **); extern struct pex_obj *collect_execute (const char *, char **, const char *, - const char *); + const char *, int flags); extern void collect_exit (int) ATTRIBUTE_NORETURN; diff --git a/gcc/combine.c b/gcc/combine.c index 35ab576d612..80c538ec490 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -321,7 +321,7 @@ static rtx *uid_log_links; static int label_tick; -/* Reset to label_tick for each label. */ +/* Reset to label_tick for each extended basic block in scanning order. */ static int label_tick_ebb_start; @@ -1010,9 +1010,6 @@ clear_log_links (void) if (INSN_P (insn)) free_INSN_LIST_list (&LOG_LINKS (insn)); } - - - /* Main entry point for combiner. F is the first insn of the function. NREGS is the first unused pseudo-reg number. @@ -1028,6 +1025,7 @@ combine_instructions (rtx f, unsigned int nregs) #endif rtx links, nextlinks; rtx first; + basic_block last_bb; int new_direct_jump_p = 0; @@ -1058,6 +1056,7 @@ combine_instructions (rtx f, unsigned int nregs) problems when, for example, we have j <<= 1 in a loop. */ nonzero_sign_valid = 0; + label_tick = label_tick_ebb_start = 1; /* Scan all SETs and see if we can deduce anything about what bits are known to be zero for some registers and how many copies @@ -1067,18 +1066,23 @@ combine_instructions (rtx f, unsigned int nregs) for what bits are known to be set. */ setup_incoming_promotions (first); + /* Allow the entry block and the first block to fall into the same EBB. + Conceptually the incoming promotions are assigned to the entry block. */ + last_bb = ENTRY_BLOCK_PTR; create_log_links (); - label_tick_ebb_start = ENTRY_BLOCK_PTR->index; FOR_EACH_BB (this_basic_block) { optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block); last_call_luid = 0; mem_last_set = -1; - label_tick = this_basic_block->index; + + label_tick++; if (!single_pred_p (this_basic_block) - || single_pred (this_basic_block)->index != label_tick - 1) + || single_pred (this_basic_block) != last_bb) label_tick_ebb_start = label_tick; + last_bb = this_basic_block; + FOR_BB_INSNS (this_basic_block, insn) if (INSN_P (insn) && BLOCK_FOR_INSN (insn)) { @@ -1109,20 +1113,23 @@ combine_instructions (rtx f, unsigned int nregs) nonzero_sign_valid = 1; /* Now scan all the insns in forward order. */ - - label_tick_ebb_start = ENTRY_BLOCK_PTR->index; + label_tick = label_tick_ebb_start = 1; init_reg_last (); setup_incoming_promotions (first); + last_bb = ENTRY_BLOCK_PTR; FOR_EACH_BB (this_basic_block) { optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block); last_call_luid = 0; mem_last_set = -1; - label_tick = this_basic_block->index; + + label_tick++; if (!single_pred_p (this_basic_block) - || single_pred (this_basic_block)->index != label_tick - 1) + || single_pred (this_basic_block) != last_bb) label_tick_ebb_start = label_tick; + last_bb = this_basic_block; + rtl_profile_for_bb (this_basic_block); for (insn = BB_HEAD (this_basic_block); insn != NEXT_INSN (BB_END (this_basic_block)); @@ -2257,68 +2264,33 @@ cleanup_auto_inc_dec (rtx src, bool after, enum machine_mode mem_mode) return x; } -#endif /* Auxiliary data structure for propagate_for_debug_stmt. */ struct rtx_subst_pair { - rtx from, to; - bool changed; -#ifdef AUTO_INC_DEC + rtx to; bool adjusted; bool after; -#endif }; -/* Clean up any auto-updates in PAIR->to the first time it is called - for a PAIR. PAIR->adjusted is used to tell whether we've cleaned - up before. */ +/* DATA points to an rtx_subst_pair. Return the value that should be + substituted. */ -static void -auto_adjust_pair (struct rtx_subst_pair *pair ATTRIBUTE_UNUSED) +static rtx +propagate_for_debug_subst (rtx from ATTRIBUTE_UNUSED, void *data) { -#ifdef AUTO_INC_DEC + struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data; + if (!pair->adjusted) { pair->adjusted = true; pair->to = cleanup_auto_inc_dec (pair->to, pair->after, VOIDmode); + return pair->to; } -#endif -} - -/* If *LOC is the same as FROM in the struct rtx_subst_pair passed as - DATA, replace it with a copy of TO. Handle SUBREGs of *LOC as - well. */ - -static int -propagate_for_debug_subst (rtx *loc, void *data) -{ - struct rtx_subst_pair *pair = (struct rtx_subst_pair *)data; - rtx from = pair->from, to = pair->to; - rtx x = *loc, s = x; - - if (rtx_equal_p (x, from) - || (GET_CODE (x) == SUBREG && rtx_equal_p ((s = SUBREG_REG (x)), from))) - { - auto_adjust_pair (pair); - if (pair->to != to) - to = pair->to; - else - to = copy_rtx (to); - if (s != x) - { - gcc_assert (GET_CODE (x) == SUBREG && SUBREG_REG (x) == s); - to = simplify_gen_subreg (GET_MODE (x), to, - GET_MODE (from), SUBREG_BYTE (x)); - } - *loc = wrap_constant (GET_MODE (x), to); - pair->changed = true; - return -1; - } - - return 0; + return copy_rtx (pair->to); } +#endif /* Replace occurrences of DEST with SRC in DEBUG_INSNs between INSN and LAST. If MOVE holds, debug insns must also be moved past @@ -2327,14 +2299,11 @@ propagate_for_debug_subst (rtx *loc, void *data) static void propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move) { - struct rtx_subst_pair p; - rtx next, move_pos = move ? last : NULL_RTX; - - p.from = dest; - p.to = src; - p.changed = false; + rtx next, move_pos = move ? last : NULL_RTX, loc; #ifdef AUTO_INC_DEC + struct rtx_subst_pair p; + p.to = src; p.adjusted = false; p.after = move; #endif @@ -2346,11 +2315,15 @@ propagate_for_debug (rtx insn, rtx last, rtx dest, rtx src, bool move) next = NEXT_INSN (insn); if (DEBUG_INSN_P (insn)) { - for_each_rtx (&INSN_VAR_LOCATION_LOC (insn), - propagate_for_debug_subst, &p); - if (!p.changed) +#ifdef AUTO_INC_DEC + loc = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn), + dest, propagate_for_debug_subst, &p); +#else + loc = simplify_replace_rtx (INSN_VAR_LOCATION_LOC (insn), dest, src); +#endif + if (loc == INSN_VAR_LOCATION_LOC (insn)) continue; - p.changed = false; + INSN_VAR_LOCATION_LOC (insn) = loc; if (move_pos) { remove_insn (insn); @@ -4186,9 +4159,12 @@ find_split_point (rtx *loc, rtx insn) if (GET_CODE (XEXP (x, 0)) == CONST || GET_CODE (XEXP (x, 0)) == SYMBOL_REF) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); + SUBST (XEXP (x, 0), - gen_rtx_LO_SUM (Pmode, - gen_rtx_HIGH (Pmode, XEXP (x, 0)), + gen_rtx_LO_SUM (address_mode, + gen_rtx_HIGH (address_mode, XEXP (x, 0)), XEXP (x, 0))); return &XEXP (XEXP (x, 0), 0); } @@ -4201,7 +4177,8 @@ find_split_point (rtx *loc, rtx insn) it will not remain in the result. */ if (GET_CODE (XEXP (x, 0)) == PLUS && CONST_INT_P (XEXP (XEXP (x, 0), 1)) - && ! memory_address_p (GET_MODE (x), XEXP (x, 0))) + && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0), + MEM_ADDR_SPACE (x))) { rtx reg = regno_reg_rtx[FIRST_PSEUDO_REGISTER]; rtx seq = combine_split_insns (gen_rtx_SET (VOIDmode, reg, @@ -4224,8 +4201,9 @@ find_split_point (rtx *loc, rtx insn) && NONJUMP_INSN_P (NEXT_INSN (seq)) && GET_CODE (PATTERN (NEXT_INSN (seq))) == SET && SET_DEST (PATTERN (NEXT_INSN (seq))) == reg - && memory_address_p (GET_MODE (x), - SET_SRC (PATTERN (NEXT_INSN (seq))))) + && memory_address_addr_space_p + (GET_MODE (x), SET_SRC (PATTERN (NEXT_INSN (seq))), + MEM_ADDR_SPACE (x))) { rtx src1 = SET_SRC (PATTERN (seq)); rtx src2 = SET_SRC (PATTERN (NEXT_INSN (seq))); @@ -4264,7 +4242,8 @@ find_split_point (rtx *loc, rtx insn) /* If we have a PLUS whose first operand is complex, try computing it separately by making a split there. */ if (GET_CODE (XEXP (x, 0)) == PLUS - && ! memory_address_p (GET_MODE (x), XEXP (x, 0)) + && ! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0), + MEM_ADDR_SPACE (x)) && ! OBJECT_P (XEXP (XEXP (x, 0), 0)) && ! (GET_CODE (XEXP (XEXP (x, 0), 0)) == SUBREG && OBJECT_P (SUBREG_REG (XEXP (XEXP (x, 0), 0))))) @@ -8811,6 +8790,12 @@ distribute_and_simplify_rtx (rtx x, int n) enum rtx_code outer_code, inner_code; rtx decomposed, distributed, inner_op0, inner_op1, new_op0, new_op1, tmp; + /* Distributivity is not true for floating point as it can change the + value. So we don't do it unless -funsafe-math-optimizations. */ + if (FLOAT_MODE_P (GET_MODE (x)) + && ! flag_unsafe_math_optimizations) + return NULL_RTX; + decomposed = XEXP (x, n); if (!ARITHMETIC_P (decomposed)) return NULL_RTX; @@ -11482,6 +11467,22 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) { int zero_extended; + /* If this is a test for negative, we can make an explicit + test of the sign bit. Test this first so we can use + a paradoxical subreg to extend OP0. */ + + if (op1 == const0_rtx && (code == LT || code == GE) + && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) + { + op0 = simplify_gen_binary (AND, tmode, + gen_lowpart (tmode, op0), + GEN_INT ((HOST_WIDE_INT) 1 + << (GET_MODE_BITSIZE (mode) + - 1))); + code = (code == LT) ? NE : EQ; + break; + } + /* If the only nonzero bits in OP0 and OP1 are those in the narrower mode and this is an equality or unsigned comparison, we can use the wider mode. Similarly for sign-extended @@ -11512,27 +11513,20 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) XEXP (op0, 0)), gen_lowpart (tmode, XEXP (op0, 1))); - - op0 = gen_lowpart (tmode, op0); - if (zero_extended && CONST_INT_P (op1)) - op1 = GEN_INT (INTVAL (op1) & GET_MODE_MASK (mode)); - op1 = gen_lowpart (tmode, op1); - break; - } - - /* If this is a test for negative, we can make an explicit - test of the sign bit. */ - - if (op1 == const0_rtx && (code == LT || code == GE) - && GET_MODE_BITSIZE (mode) <= HOST_BITS_PER_WIDE_INT) - { - op0 = simplify_gen_binary (AND, tmode, - gen_lowpart (tmode, op0), - GEN_INT ((HOST_WIDE_INT) 1 - << (GET_MODE_BITSIZE (mode) - - 1))); - code = (code == LT) ? NE : EQ; - break; + else + { + if (zero_extended) + { + op0 = simplify_gen_unary (ZERO_EXTEND, tmode, op0, mode); + op1 = simplify_gen_unary (ZERO_EXTEND, tmode, op1, mode); + } + else + { + op0 = simplify_gen_unary (SIGN_EXTEND, tmode, op0, mode); + op1 = simplify_gen_unary (SIGN_EXTEND, tmode, op1, mode); + } + break; + } } } @@ -11752,12 +11746,10 @@ record_value_for_reg (rtx reg, rtx insn, rtx value) case, we must replace it with (clobber (const_int 0)) to prevent infinite loops. */ rsp = VEC_index (reg_stat_type, reg_stat, regno); - if (value && ! get_last_value_validate (&value, insn, - rsp->last_set_label, 0)) + if (value && !get_last_value_validate (&value, insn, label_tick, 0)) { value = copy_rtx (value); - if (! get_last_value_validate (&value, insn, - rsp->last_set_label, 1)) + if (!get_last_value_validate (&value, insn, label_tick, 1)) value = 0; } @@ -12049,15 +12041,14 @@ check_promoted_subreg (rtx insn, rtx x) } } -/* Utility routine for the following function. Verify that all the registers - mentioned in *LOC are valid when *LOC was part of a value set when - label_tick == TICK. Return 0 if some are not. - - If REPLACE is nonzero, replace the invalid reference with - (clobber (const_int 0)) and return 1. This replacement is useful because - we often can get useful information about the form of a value (e.g., if - it was produced by a shift that always produces -1 or 0) even though - we don't know exactly what registers it was produced from. */ +/* Verify that all the registers and memory references mentioned in *LOC are + still valid. *LOC was part of a value set in INSN when label_tick was + equal to TICK. Return 0 if some are not. If REPLACE is nonzero, replace + the invalid references with (clobber (const_int 0)) and return 1. This + replacement is useful because we often can get useful information about + the form of a value (e.g., if it was produced by a shift that always + produces -1 or 0) even though we don't know exactly what registers it + was produced from. */ static int get_last_value_validate (rtx *loc, rtx insn, int tick, int replace) @@ -12093,11 +12084,12 @@ get_last_value_validate (rtx *loc, rtx insn, int tick, int replace) return 1; } - /* If this is a memory reference, make sure that there were - no stores after it that might have clobbered the value. We don't - have alias info, so we assume any store invalidates it. */ + /* If this is a memory reference, make sure that there were no stores after + it that might have clobbered the value. We don't have alias info, so we + assume any store invalidates it. Moreover, we only have local UIDs, so + we also assume that there were stores in the intervening basic blocks. */ else if (MEM_P (x) && !MEM_READONLY_P (x) - && DF_INSN_LUID (insn) <= mem_last_set) + && (tick != label_tick || DF_INSN_LUID (insn) <= mem_last_set)) { if (replace) *loc = gen_rtx_CLOBBER (GET_MODE (x), const0_rtx); @@ -12207,16 +12199,14 @@ get_last_value (const_rtx x) return 0; /* If the value has all its registers valid, return it. */ - if (get_last_value_validate (&value, rsp->last_set, - rsp->last_set_label, 0)) + if (get_last_value_validate (&value, rsp->last_set, rsp->last_set_label, 0)) return value; /* Otherwise, make a copy and replace any invalid register with (clobber (const_int 0)). If that fails for some reason, return 0. */ value = copy_rtx (value); - if (get_last_value_validate (&value, rsp->last_set, - rsp->last_set_label, 1)) + if (get_last_value_validate (&value, rsp->last_set, rsp->last_set_label, 1)) return value; return 0; diff --git a/gcc/common.opt b/gcc/common.opt index 189f476a09e..77967f89dfd 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -502,6 +502,10 @@ femit-class-debug-always Common Report Var(flag_emit_class_debug_always) Init(0) Do not suppress C++ class debug information. +fenable-icf-debug +Common Report Var(flag_enable_icf_debug) +Generate debug information to support Identical Code Folding (ICF) + fexceptions Common Report Var(flag_exceptions) Optimization Enable exception handling @@ -713,6 +717,11 @@ fira-coalesce Common Report Var(flag_ira_coalesce) Init(0) Do optimistic coalescing. +fira-loop-pressure +Common Report Var(flag_ira_loop_pressure) +Use IRA based register pressure calculation +in RTL loop optimizations. + fira-share-save-slots Common Report Var(flag_ira_share_save_slots) Init(1) Share slots for saving different hard registers. @@ -749,6 +758,19 @@ floop-optimize Common Does nothing. Preserved for backward compatibility. +flto +Common Var(flag_lto) +Enable link-time optimization. + +; The initial value of -1 comes from Z_DEFAULT_COMPRESSION in zlib.h. +flto-compression-level= +Common Joined UInteger Var(flag_lto_compression_level) Init(-1) +-flto-compression-level= Use zlib compression level for IL + +flto-report +Common Report Var(flag_lto_report) Init(0) Optimization +Report various link-time optimization statistics + fmath-errno Common Report Var(flag_errno_math) Init(1) Optimization Set errno after built-in math functions @@ -1369,6 +1391,9 @@ funwind-tables Common Report Var(flag_unwind_tables) Optimization Just generate unwind tables for exception handling +fuse-linker-plugin +Common Undocumented + fvar-tracking Common Report Var(flag_var_tracking) VarExists Optimization Perform variable tracking @@ -1432,6 +1457,10 @@ fweb Common Report Var(flag_web) Init(2) Optimization Construct webs and split unrelated uses of single variable +fwhopr +Common Var(flag_whopr) +Enable partitioned link-time optimization. + ftree-builtin-call-dce Common Report Var(flag_tree_builtin_call_dce) Init(0) Optimization Enable conditional dead code elimination for builtin calls diff --git a/gcc/config.gcc b/gcc/config.gcc index 1b0194b0589..1d3c3fc84f8 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -287,8 +287,8 @@ i[34567]86-*-*) extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h - immintrin.h x86intrin.h avxintrin.h - ia32intrin.h cross-stdarg.h" + immintrin.h x86intrin.h avxintrin.h xopintrin.h + ia32intrin.h cross-stdarg.h lwpintrin.h" ;; x86_64-*-*) cpu_type=i386 @@ -297,8 +297,8 @@ x86_64-*-*) extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h nmmintrin.h bmmintrin.h fma4intrin.h wmmintrin.h - immintrin.h x86intrin.h avxintrin.h - ia32intrin.h cross-stdarg.h" + immintrin.h x86intrin.h avxintrin.h xopintrin.h + ia32intrin.h cross-stdarg.h lwpintrin.h" need_64bit_hwint=yes ;; ia64-*-*) @@ -327,7 +327,7 @@ powerpc*-*-*) extra_headers="ppc-asm.h altivec.h spe.h ppu_intrinsics.h paired.h spu2vmx.h vec_types.h si2vmx.h" need_64bit_hwint=yes case x$with_cpu in - xpowerpc64|xdefault64|x6[23]0|x970|xG5|xpower[34567]|xpower6x|xrs64a|xcell) + xpowerpc64|xdefault64|x6[23]0|x970|xG5|xpower[34567]|xpower6x|xrs64a|xcell|xa2) cpu_is_64bit=yes ;; esac @@ -722,7 +722,7 @@ arm*-*-linux*) # ARM GNU/Linux with ELF case ${target} in arm*-*-linux-*eabi) tm_file="$tm_file arm/bpabi.h arm/linux-eabi.h" - tmake_file="$tmake_file arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi" + tmake_file="$tmake_file arm/t-arm-elf arm/t-bpabi arm/t-linux-eabi t-slibgcc-libgcc" # The BPABI long long divmod functions return a 128-bit value in # registers r0-r3. Correctly modeling that requires the use of # TImode. @@ -2077,9 +2077,12 @@ rs6000-ibm-aix[6789].* | powerpc-ibm-aix[6789].*) use_gcc_stdint=wrap extra_headers=altivec.h ;; +rx-*-elf*) + tm_file="dbxelf.h elfos.h svr4.h newlib-stdint.h ${tm_file} ../../libgcc/config/rx/rx-abi.h" + tmake_file="${tmake_file} rx/t-rx" + ;; s390-*-linux*) tm_file="s390/s390.h dbxelf.h elfos.h svr4.h linux.h glibc-stdint.h s390/linux.h" - tmake_file="${tmake_file} t-dfprules s390/t-crtstuff s390/t-linux" ;; s390x-*-linux*) tm_file="s390/s390x.h s390/s390.h dbxelf.h elfos.h svr4.h linux.h glibc-stdint.h s390/linux.h" @@ -2087,7 +2090,7 @@ s390x-*-linux*) md_file=s390/s390.md extra_modes=s390/s390-modes.def out_file=s390/s390.c - tmake_file="${tmake_file} t-dfprules s390/t-crtstuff s390/t-linux s390/t-linux64" + tmake_file="${tmake_file} s390/t-linux64" ;; s390x-ibm-tpf*) tm_file="s390/s390x.h s390/s390.h dbxelf.h elfos.h svr4.h s390/tpf.h" @@ -2096,7 +2099,6 @@ s390x-ibm-tpf*) extra_modes=s390/s390-modes.def out_file=s390/s390.c extra_parts="crtbeginS.o crtendS.o" - tmake_file="s390/t-crtstuff s390/t-tpf" thread_file='tpf' extra_options="${extra_options} s390/tpf.opt" ;; @@ -2447,7 +2449,7 @@ sparc64-*-netbsd*) spu-*-elf*) tm_file="dbxelf.h elfos.h spu/spu-elf.h spu/spu.h newlib-stdint.h" tmake_file="spu/t-spu-elf" - extra_headers="spu_intrinsics.h spu_internals.h vmx2spu.h spu_mfcio.h vec_types.h" + extra_headers="spu_intrinsics.h spu_internals.h vmx2spu.h spu_mfcio.h vec_types.h spu_cache.h" extra_modes=spu/spu-modes.def c_target_objs="${c_target_objs} spu-c.o" cxx_target_objs="${cxx_target_objs} spu-c.o" @@ -2501,7 +2503,7 @@ v850-*-*) ;; vax-*-linux*) tm_file="${tm_file} dbxelf.h elfos.h svr4.h linux.h vax/elf.h vax/linux.h" - tmake_file=vax/t-linux + tmake_file="${tmake_file} vax/t-linux" ;; vax-*-netbsdelf*) tm_file="${tm_file} elfos.h netbsd.h netbsd-elf.h vax/elf.h vax/netbsd-elf.h" @@ -3068,9 +3070,9 @@ case "${target}" in | power | power[234567] | power6x | powerpc | powerpc64 \ | rios | rios1 | rios2 | rsc | rsc1 | rs64a \ | 401 | 403 | 405 | 405fp | 440 | 440fp | 464 | 464fp \ - | 505 | 601 | 602 | 603 | 603e | ec603e | 604 \ - | 604e | 620 | 630 | 740 | 750 | 7400 | 7450 \ - | e300c[23] | 854[08] | e500mc \ + | 476 | 476fp | 505 | 601 | 602 | 603 | 603e | ec603e \ + | 604 | 604e | 620 | 630 | 740 | 750 | 7400 | 7450 \ + | a2 | e300c[23] | 854[08] | e500mc \ | 801 | 821 | 823 | 860 | 970 | G3 | G4 | G5 | cell) # OK ;; diff --git a/gcc/config.host b/gcc/config.host index 4affcb06b17..9738345c8a2 100644 --- a/gcc/config.host +++ b/gcc/config.host @@ -130,7 +130,7 @@ case ${host} in ;; esac case ${host} in - *-*-linux* ) + *-*-linux* | *-*-freebsd*) if test "${GCC}:${ac_cv_sizeof_long}" = yes:4; then # On powerpc*-*-linux* use -Wl,--relax to link cc1, # if ld is new enough, otherwise force -O1 in CFLAGS. diff --git a/gcc/config.in b/gcc/config.in index 12573fd1579..a3e9069e129 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -113,6 +113,12 @@ #endif +/* Define to enable LTO support. */ +#ifndef USED_FOR_TARGET +#undef ENABLE_LTO +#endif + + /* Define to 1 if translation of program messages to the user's native language is requested. */ #ifndef USED_FOR_TARGET @@ -205,6 +211,12 @@ #endif +/* Define if your assembler supports the DCI/ICI instructions. */ +#ifndef USED_FOR_TARGET +#undef HAVE_AS_DCI +#endif + + /* Define if your assembler supports the --debug-prefix-map option. */ #ifndef USED_FOR_TARGET #undef HAVE_AS_DEBUG_PREFIX_MAP @@ -303,6 +315,12 @@ #endif +/* Define if your assembler supports the swap suffix. */ +#ifndef USED_FOR_TARGET +#undef HAVE_AS_IX86_SWAP +#endif + + /* Define if your assembler supports the lituse_jsrdirect relocation. */ #ifndef USED_FOR_TARGET #undef HAVE_AS_JSRDIRECT_RELOCS @@ -1453,6 +1471,12 @@ #endif +/* Define if libelf is in use. */ +#ifndef USED_FOR_TARGET +#undef HAVE_libelf +#endif + + /* Define if mpc is in use. */ #ifndef USED_FOR_TARGET #undef HAVE_mpc diff --git a/gcc/config/alpha/osf.h b/gcc/config/alpha/osf.h index 2b5165c0754..81c12aa14fc 100644 --- a/gcc/config/alpha/osf.h +++ b/gcc/config/alpha/osf.h @@ -167,10 +167,6 @@ __enable_execute_stack (void *addr) \ #define LD_INIT_SWITCH "-init" #define LD_FINI_SWITCH "-fini" -/* The linker needs a space after "-o". This allows -oldstyle_liblookup to - be passed to ld. */ -#define SWITCHES_NEED_SPACES "o" - /* Select a format to encode pointers in exception handling data. CODE is 0 for data, 1 for code labels, 2 for function pointers. GLOBAL is true if the symbol may be affected by dynamic relocations. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index cd5a0ed1403..4c7fcb65854 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -133,11 +133,12 @@ static enum machine_mode arm_promote_function_mode (const_tree, const_tree, int); static bool arm_return_in_memory (const_tree, const_tree); static rtx arm_function_value (const_tree, const_tree, bool); -static rtx arm_libcall_value (enum machine_mode, rtx); +static rtx arm_libcall_value (enum machine_mode, const_rtx); static void arm_internal_label (FILE *, const char *, unsigned long); static void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); +static bool arm_have_conditional_execution (void); static bool arm_rtx_costs_1 (rtx, enum rtx_code, int*, bool); static bool arm_size_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *); static bool arm_slowmul_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool); @@ -445,6 +446,9 @@ static const struct attribute_spec arm_attribute_table[] = #define TARGET_HAVE_TLS true #endif +#undef TARGET_HAVE_CONDITIONAL_EXECUTION +#define TARGET_HAVE_CONDITIONAL_EXECUTION arm_have_conditional_execution + #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM arm_cannot_force_const_mem @@ -520,14 +524,11 @@ enum processor_type arm_tune = arm_none; /* The default processor used if not overridden by commandline. */ static enum processor_type arm_default_cpu = arm_none; -/* Which floating point model to use. */ -enum arm_fp_model arm_fp_model; - -/* Which floating point hardware is available. */ -enum fputype arm_fpu_arch; - /* Which floating point hardware to schedule for. */ -enum fputype arm_fpu_tune; +int arm_fpu_attr; + +/* Which floating popint hardware to use. */ +const struct arm_fpu_desc *arm_fpu_desc; /* Whether to use floating point hardware. */ enum float_abi_type arm_float_abi; @@ -805,46 +806,21 @@ static struct arm_cpu_select arm_select[] = char arm_arch_name[] = "__ARM_ARCH_0UNK__"; -struct fpu_desc -{ - const char * name; - enum fputype fpu; -}; - - /* Available values for -mfpu=. */ -static const struct fpu_desc all_fpus[] = -{ - {"fpa", FPUTYPE_FPA}, - {"fpe2", FPUTYPE_FPA_EMU2}, - {"fpe3", FPUTYPE_FPA_EMU2}, - {"maverick", FPUTYPE_MAVERICK}, - {"vfp", FPUTYPE_VFP}, - {"vfp3", FPUTYPE_VFP3}, - {"vfpv3", FPUTYPE_VFP3}, - {"vfpv3-d16", FPUTYPE_VFP3D16}, - {"neon", FPUTYPE_NEON}, - {"neon-fp16", FPUTYPE_NEON_FP16} -}; - - -/* Floating point models used by the different hardware. - See fputype in arm.h. */ - -static const enum arm_fp_model fp_model_for_fpu[] = -{ - /* No FP hardware. */ - ARM_FP_MODEL_UNKNOWN, /* FPUTYPE_NONE */ - ARM_FP_MODEL_FPA, /* FPUTYPE_FPA */ - ARM_FP_MODEL_FPA, /* FPUTYPE_FPA_EMU2 */ - ARM_FP_MODEL_FPA, /* FPUTYPE_FPA_EMU3 */ - ARM_FP_MODEL_MAVERICK, /* FPUTYPE_MAVERICK */ - ARM_FP_MODEL_VFP, /* FPUTYPE_VFP */ - ARM_FP_MODEL_VFP, /* FPUTYPE_VFP3D16 */ - ARM_FP_MODEL_VFP, /* FPUTYPE_VFP3 */ - ARM_FP_MODEL_VFP, /* FPUTYPE_NEON */ - ARM_FP_MODEL_VFP /* FPUTYPE_NEON_FP16 */ +static const struct arm_fpu_desc all_fpus[] = +{ + {"fpa", ARM_FP_MODEL_FPA, 0, 0, false, false}, + {"fpe2", ARM_FP_MODEL_FPA, 2, 0, false, false}, + {"fpe3", ARM_FP_MODEL_FPA, 3, 0, false, false}, + {"maverick", ARM_FP_MODEL_MAVERICK, 0, 0, false, false}, + {"vfp", ARM_FP_MODEL_VFP, 2, VFP_REG_D16, false, false}, + {"vfpv3", ARM_FP_MODEL_VFP, 3, VFP_REG_D32, false, false}, + {"vfpv3-d16", ARM_FP_MODEL_VFP, 3, VFP_REG_D16, false, false}, + {"neon", ARM_FP_MODEL_VFP, 3, VFP_REG_D32, true , false}, + {"neon-fp16", ARM_FP_MODEL_VFP, 3, VFP_REG_D32, true , true }, + /* Compatibility aliases. */ + {"vfp3", ARM_FP_MODEL_VFP, 3, VFP_REG_D32, false, false}, }; @@ -1298,13 +1274,6 @@ arm_override_options (void) enum processor_type target_arch_cpu = arm_none; enum processor_type selected_cpu = arm_none; - /* Ideally we would want to use CFI directives to generate - debug info. However this also creates the .eh_frame - section, so disable them until GAS can handle - this properly. See PR40521. */ - if (TARGET_AAPCS_BASED) - flag_dwarf2_cfi_asm = 0; - /* Set up the flags based on the cpu/architecture selected by the user. */ for (i = ARRAY_SIZE (arm_select); i--;) { @@ -1618,7 +1587,6 @@ arm_override_options (void) if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT) error ("iwmmxt abi requires an iwmmxt capable cpu"); - arm_fp_model = ARM_FP_MODEL_UNKNOWN; if (target_fpu_name == NULL && target_fpe_name != NULL) { if (streq (target_fpe_name, "2")) @@ -1629,46 +1597,52 @@ arm_override_options (void) error ("invalid floating point emulation option: -mfpe=%s", target_fpe_name); } - if (target_fpu_name != NULL) - { - /* The user specified a FPU. */ - for (i = 0; i < ARRAY_SIZE (all_fpus); i++) - { - if (streq (all_fpus[i].name, target_fpu_name)) - { - arm_fpu_arch = all_fpus[i].fpu; - arm_fpu_tune = arm_fpu_arch; - arm_fp_model = fp_model_for_fpu[arm_fpu_arch]; - break; - } - } - if (arm_fp_model == ARM_FP_MODEL_UNKNOWN) - error ("invalid floating point option: -mfpu=%s", target_fpu_name); - } - else + + if (target_fpu_name == NULL) { #ifdef FPUTYPE_DEFAULT - /* Use the default if it is specified for this platform. */ - arm_fpu_arch = FPUTYPE_DEFAULT; - arm_fpu_tune = FPUTYPE_DEFAULT; + target_fpu_name = FPUTYPE_DEFAULT; #else - /* Pick one based on CPU type. */ - /* ??? Some targets assume FPA is the default. - if ((insn_flags & FL_VFP) != 0) - arm_fpu_arch = FPUTYPE_VFP; - else - */ if (arm_arch_cirrus) - arm_fpu_arch = FPUTYPE_MAVERICK; + target_fpu_name = "maverick"; else - arm_fpu_arch = FPUTYPE_FPA_EMU2; + target_fpu_name = "fpe2"; #endif - if (tune_flags & FL_CO_PROC && arm_fpu_arch == FPUTYPE_FPA_EMU2) - arm_fpu_tune = FPUTYPE_FPA; + } + + arm_fpu_desc = NULL; + for (i = 0; i < ARRAY_SIZE (all_fpus); i++) + { + if (streq (all_fpus[i].name, target_fpu_name)) + { + arm_fpu_desc = &all_fpus[i]; + break; + } + } + if (!arm_fpu_desc) + error ("invalid floating point option: -mfpu=%s", target_fpu_name); + + switch (arm_fpu_desc->model) + { + case ARM_FP_MODEL_FPA: + if (arm_fpu_desc->rev == 2) + arm_fpu_attr = FPU_FPE2; + else if (arm_fpu_desc->rev == 3) + arm_fpu_attr = FPU_FPE3; else - arm_fpu_tune = arm_fpu_arch; - arm_fp_model = fp_model_for_fpu[arm_fpu_arch]; - gcc_assert (arm_fp_model != ARM_FP_MODEL_UNKNOWN); + arm_fpu_attr = FPU_FPA; + break; + + case ARM_FP_MODEL_MAVERICK: + arm_fpu_attr = FPU_MAVERICK; + break; + + case ARM_FP_MODEL_VFP: + arm_fpu_attr = FPU_VFP; + break; + + default: + gcc_unreachable(); } if (target_float_abi_name != NULL) @@ -1690,7 +1664,7 @@ arm_override_options (void) arm_float_abi = TARGET_DEFAULT_FLOAT_ABI; if (TARGET_AAPCS_BASED - && (arm_fp_model == ARM_FP_MODEL_FPA)) + && (arm_fpu_desc->model == ARM_FP_MODEL_FPA)) error ("FPA is unsupported in the AAPCS"); if (TARGET_AAPCS_BASED) @@ -1718,7 +1692,7 @@ arm_override_options (void) /* If soft-float is specified then don't use FPU. */ if (TARGET_SOFT_FLOAT) - arm_fpu_arch = FPUTYPE_NONE; + arm_fpu_attr = FPU_NONE; if (TARGET_AAPCS_BASED) { @@ -1745,8 +1719,7 @@ arm_override_options (void) /* For arm2/3 there is no need to do any scheduling if there is only a floating point emulator, or we are doing software floating-point. */ if ((TARGET_SOFT_FLOAT - || arm_fpu_tune == FPUTYPE_FPA_EMU2 - || arm_fpu_tune == FPUTYPE_FPA_EMU3) + || (TARGET_FPA && arm_fpu_desc->rev)) && (tune_flags & FL_MODE32) == 0) flag_schedule_insns = flag_schedule_insns_after_reload = 0; @@ -1871,6 +1844,23 @@ arm_override_options (void) max_insns_skipped = 3; } + /* Hot/Cold partitioning is not currently supported, since we can't + handle literal pool placement in that case. */ + if (flag_reorder_blocks_and_partition) + { + inform (input_location, + "-freorder-blocks-and-partition not supported on this architecture"); + flag_reorder_blocks_and_partition = 0; + flag_reorder_blocks = 1; + } + + /* Ideally we would want to use CFI directives to generate + debug info. However this also creates the .eh_frame + section, so disable them until GAS can handle + this properly. See PR40521. */ + if (TARGET_AAPCS_BASED) + flag_dwarf2_cfi_asm = 0; + /* Register global variables with the garbage collector. */ arm_add_gc_roots (); } @@ -2393,20 +2383,24 @@ arm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn, 1); } -/* Return the number of ARM instructions required to synthesize the given - constant. */ +/* Return the number of instructions required to synthesize the given + constant, if we start emitting them from bit-position I. */ static int count_insns_for_constant (HOST_WIDE_INT remainder, int i) { HOST_WIDE_INT temp1; + int step_size = TARGET_ARM ? 2 : 1; int num_insns = 0; + + gcc_assert (TARGET_ARM || i == 0); + do { int end; if (i <= 0) i += 32; - if (remainder & (3 << (i - 2))) + if (remainder & (((1 << step_size) - 1) << (i - step_size))) { end = i - 8; if (end < 0) @@ -2415,13 +2409,77 @@ count_insns_for_constant (HOST_WIDE_INT remainder, int i) | ((i < end) ? (0xff >> (32 - end)) : 0)); remainder &= ~temp1; num_insns++; - i -= 6; + i -= 8 - step_size; } - i -= 2; + i -= step_size; } while (remainder); return num_insns; } +static int +find_best_start (unsigned HOST_WIDE_INT remainder) +{ + int best_consecutive_zeros = 0; + int i; + int best_start = 0; + + /* If we aren't targetting ARM, the best place to start is always at + the bottom. */ + if (! TARGET_ARM) + return 0; + + for (i = 0; i < 32; i += 2) + { + int consecutive_zeros = 0; + + if (!(remainder & (3 << i))) + { + while ((i < 32) && !(remainder & (3 << i))) + { + consecutive_zeros += 2; + i += 2; + } + if (consecutive_zeros > best_consecutive_zeros) + { + best_consecutive_zeros = consecutive_zeros; + best_start = i - consecutive_zeros; + } + i -= 2; + } + } + + /* So long as it won't require any more insns to do so, it's + desirable to emit a small constant (in bits 0...9) in the last + insn. This way there is more chance that it can be combined with + a later addressing insn to form a pre-indexed load or store + operation. Consider: + + *((volatile int *)0xe0000100) = 1; + *((volatile int *)0xe0000110) = 2; + + We want this to wind up as: + + mov rA, #0xe0000000 + mov rB, #1 + str rB, [rA, #0x100] + mov rB, #2 + str rB, [rA, #0x110] + + rather than having to synthesize both large constants from scratch. + + Therefore, we calculate how many insns would be required to emit + the constant starting from `best_start', and also starting from + zero (i.e. with bit 31 first to be output). If `best_start' doesn't + yield a shorter sequence, we may as well use zero. */ + if (best_start != 0 + && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder) + && (count_insns_for_constant (remainder, 0) <= + count_insns_for_constant (remainder, best_start))) + best_start = 0; + + return best_start; +} + /* Emit an instruction with the indicated PATTERN. If COND is non-NULL, conditionalize the execution of the instruction on COND being true. */ @@ -2445,6 +2503,7 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond, { int can_invert = 0; int can_negate = 0; + int final_invert = 0; int can_negate_initial = 0; int can_shift = 0; int i; @@ -2456,6 +2515,7 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond, int insns = 0; unsigned HOST_WIDE_INT temp1, temp2; unsigned HOST_WIDE_INT remainder = val & 0xffffffff; + int step_size = TARGET_ARM ? 2 : 1; /* Find out which operations are safe for a given CODE. Also do a quick check for degenerate cases; these can occur when DImode operations @@ -2529,14 +2589,15 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond, return 1; } - /* We don't know how to handle other cases yet. */ - gcc_assert (remainder == 0xffffffff); - - if (generate) - emit_constant_insn (cond, - gen_rtx_SET (VOIDmode, target, - gen_rtx_NOT (mode, source))); - return 1; + if (remainder == 0xffffffff) + { + if (generate) + emit_constant_insn (cond, + gen_rtx_SET (VOIDmode, target, + gen_rtx_NOT (mode, source))); + return 1; + } + break; case MINUS: /* We treat MINUS as (val - source), since (source - val) is always @@ -2987,9 +3048,25 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond, if ((code == AND) || (code != IOR && can_invert && num_bits_set > 16)) - remainder = (~remainder) & 0xffffffff; + remainder ^= 0xffffffff; else if (code == PLUS && num_bits_set > 16) remainder = (-remainder) & 0xffffffff; + + /* For XOR, if more than half the bits are set and there's a sequence + of more than 8 consecutive ones in the pattern then we can XOR by the + inverted constant and then invert the final result; this may save an + instruction and might also lead to the final mvn being merged with + some other operation. */ + else if (code == XOR && num_bits_set > 16 + && (count_insns_for_constant (remainder ^ 0xffffffff, + find_best_start + (remainder ^ 0xffffffff)) + < count_insns_for_constant (remainder, + find_best_start (remainder)))) + { + remainder ^= 0xffffffff; + final_invert = 1; + } else { can_invert = 0; @@ -3008,63 +3085,8 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond, /* ??? Use thumb2 replicated constants when the high and low halfwords are the same. */ { - int best_start = 0; - if (!TARGET_THUMB2) - { - int best_consecutive_zeros = 0; - - for (i = 0; i < 32; i += 2) - { - int consecutive_zeros = 0; - - if (!(remainder & (3 << i))) - { - while ((i < 32) && !(remainder & (3 << i))) - { - consecutive_zeros += 2; - i += 2; - } - if (consecutive_zeros > best_consecutive_zeros) - { - best_consecutive_zeros = consecutive_zeros; - best_start = i - consecutive_zeros; - } - i -= 2; - } - } - - /* So long as it won't require any more insns to do so, it's - desirable to emit a small constant (in bits 0...9) in the last - insn. This way there is more chance that it can be combined with - a later addressing insn to form a pre-indexed load or store - operation. Consider: - - *((volatile int *)0xe0000100) = 1; - *((volatile int *)0xe0000110) = 2; - - We want this to wind up as: - - mov rA, #0xe0000000 - mov rB, #1 - str rB, [rA, #0x100] - mov rB, #2 - str rB, [rA, #0x110] - - rather than having to synthesize both large constants from scratch. - - Therefore, we calculate how many insns would be required to emit - the constant starting from `best_start', and also starting from - zero (i.e. with bit 31 first to be output). If `best_start' doesn't - yield a shorter sequence, we may as well use zero. */ - if (best_start != 0 - && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder) - && (count_insns_for_constant (remainder, 0) <= - count_insns_for_constant (remainder, best_start))) - best_start = 0; - } - /* Now start emitting the insns. */ - i = best_start; + i = find_best_start (remainder); do { int end; @@ -3092,7 +3114,7 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond, } else { - if (remainder && subtargets) + if ((final_invert || remainder) && subtargets) new_src = gen_reg_rtx (mode); else new_src = target; @@ -3127,21 +3149,23 @@ arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond, code = PLUS; insns++; - if (TARGET_ARM) - i -= 6; - else - i -= 7; + i -= 8 - step_size; } /* Arm allows rotates by a multiple of two. Thumb-2 allows arbitrary shifts. */ - if (TARGET_ARM) - i -= 2; - else - i--; + i -= step_size; } while (remainder); } + if (final_invert) + { + if (generate) + emit_constant_insn (cond, gen_rtx_SET (VOIDmode, target, + gen_rtx_NOT (mode, source))); + insns++; + } + return insns; } @@ -3264,7 +3288,7 @@ add_libcall (htab_t htab, rtx libcall) } static bool -arm_libcall_uses_aapcs_base (rtx libcall) +arm_libcall_uses_aapcs_base (const_rtx libcall) { static bool init_done = false; static htab_t libcall_htab; @@ -3311,7 +3335,7 @@ arm_libcall_uses_aapcs_base (rtx libcall) } rtx -arm_libcall_value (enum machine_mode mode, rtx libcall) +arm_libcall_value (enum machine_mode mode, const_rtx libcall) { if (TARGET_AAPCS_BASED && arm_pcs_default != ARM_PCS_AAPCS && GET_MODE_CLASS (mode) == MODE_FLOAT) @@ -6201,7 +6225,7 @@ thumb1_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer) else if ((outer == PLUS || outer == COMPARE) && INTVAL (x) < 256 && INTVAL (x) > -256) return 0; - else if (outer == AND + else if ((outer == IOR || outer == XOR || outer == AND) && INTVAL (x) < 256 && INTVAL (x) >= -256) return COSTS_N_INSNS (1); else if (outer == ASHIFT || outer == ASHIFTRT @@ -12269,7 +12293,7 @@ output_move_neon (rtx *operands) { /* We're only using DImode here because it's a convenient size. */ ops[0] = gen_rtx_REG (DImode, REGNO (reg) + 2 * i); - ops[1] = adjust_address (mem, SImode, 8 * i); + ops[1] = adjust_address (mem, DImode, 8 * i); if (reg_overlap_mentioned_p (ops[0], mem)) { gcc_assert (overlap == -1); @@ -13257,7 +13281,7 @@ arm_output_epilogue (rtx sibling) /* This variable is for the Virtual Frame Pointer, not VFP regs. */ int vfp_offset = offsets->frame; - if (arm_fpu_arch == FPUTYPE_FPA_EMU2) + if (TARGET_FPA_EMU2) { for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--) if (df_regs_ever_live_p (reg) && !call_used_regs[reg]) @@ -13480,7 +13504,7 @@ arm_output_epilogue (rtx sibling) SP_REGNUM, HARD_FRAME_POINTER_REGNUM); } - if (arm_fpu_arch == FPUTYPE_FPA_EMU2) + if (TARGET_FPA_EMU2) { for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++) if (df_regs_ever_live_p (reg) && !call_used_regs[reg]) @@ -14206,7 +14230,7 @@ arm_save_coproc_regs(void) /* Save any floating point call-saved registers used by this function. */ - if (arm_fpu_arch == FPUTYPE_FPA_EMU2) + if (TARGET_FPA_EMU2) { for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--) if (df_regs_ever_live_p (reg) && !call_used_regs[reg]) @@ -19688,45 +19712,8 @@ arm_file_start (void) } else { - int set_float_abi_attributes = 0; - switch (arm_fpu_arch) - { - case FPUTYPE_FPA: - fpu_name = "fpa"; - break; - case FPUTYPE_FPA_EMU2: - fpu_name = "fpe2"; - break; - case FPUTYPE_FPA_EMU3: - fpu_name = "fpe3"; - break; - case FPUTYPE_MAVERICK: - fpu_name = "maverick"; - break; - case FPUTYPE_VFP: - fpu_name = "vfp"; - set_float_abi_attributes = 1; - break; - case FPUTYPE_VFP3D16: - fpu_name = "vfpv3-d16"; - set_float_abi_attributes = 1; - break; - case FPUTYPE_VFP3: - fpu_name = "vfpv3"; - set_float_abi_attributes = 1; - break; - case FPUTYPE_NEON: - fpu_name = "neon"; - set_float_abi_attributes = 1; - break; - case FPUTYPE_NEON_FP16: - fpu_name = "neon-fp16"; - set_float_abi_attributes = 1; - break; - default: - abort(); - } - if (set_float_abi_attributes) + fpu_name = arm_fpu_desc->name; + if (arm_fpu_desc->model == ARM_FP_MODEL_VFP) { if (TARGET_HARD_FLOAT) asm_fprintf (asm_out_file, "\t.eabi_attribute 27, 3\n"); @@ -21173,4 +21160,12 @@ arm_frame_pointer_required (void) || (TARGET_ARM && TARGET_APCS_FRAME && ! leaf_function_p ())); } +/* Only thumb1 can't support conditional execution, so return true if + the target is not thumb1. */ +static bool +arm_have_conditional_execution (void) +{ + return !TARGET_THUMB1; +} + #include "gt-arm.h" diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h index 9272ca51cba..2dfd22df45c 100644 --- a/gcc/config/arm/arm.h +++ b/gcc/config/arm/arm.h @@ -190,9 +190,9 @@ extern void (*arm_lang_output_object_attributes_hook)(void); #define TARGET_HARD_FLOAT (arm_float_abi != ARM_FLOAT_ABI_SOFT) /* Use hardware floating point calling convention. */ #define TARGET_HARD_FLOAT_ABI (arm_float_abi == ARM_FLOAT_ABI_HARD) -#define TARGET_FPA (arm_fp_model == ARM_FP_MODEL_FPA) -#define TARGET_MAVERICK (arm_fp_model == ARM_FP_MODEL_MAVERICK) -#define TARGET_VFP (arm_fp_model == ARM_FP_MODEL_VFP) +#define TARGET_FPA (arm_fpu_desc->model == ARM_FP_MODEL_FPA) +#define TARGET_MAVERICK (arm_fpu_desc->model == ARM_FP_MODEL_MAVERICK) +#define TARGET_VFP (arm_fpu_desc->model == ARM_FP_MODEL_VFP) #define TARGET_IWMMXT (arm_arch_iwmmxt) #define TARGET_REALLY_IWMMXT (TARGET_IWMMXT && TARGET_32BIT) #define TARGET_IWMMXT_ABI (TARGET_32BIT && arm_abi == ARM_ABI_IWMMXT) @@ -216,6 +216,8 @@ extern void (*arm_lang_output_object_attributes_hook)(void); #define TARGET_THUMB2 (TARGET_THUMB && arm_arch_thumb2) /* Thumb-1 only. */ #define TARGET_THUMB1_ONLY (TARGET_THUMB1 && !arm_arch_notm) +/* FPA emulator without LFM. */ +#define TARGET_FPA_EMU2 (TARGET_FPA && arm_fpu_desc->rev == 2) /* The following two macros concern the ability to execute coprocessor instructions for VFPv3 or NEON. TARGET_VFP3/TARGET_VFPD32 are currently @@ -223,27 +225,21 @@ extern void (*arm_lang_output_object_attributes_hook)(void); to be more careful with TARGET_NEON as noted below. */ /* FPU is has the full VFPv3/NEON register file of 32 D registers. */ -#define TARGET_VFPD32 (arm_fp_model == ARM_FP_MODEL_VFP \ - && (arm_fpu_arch == FPUTYPE_VFP3 \ - || arm_fpu_arch == FPUTYPE_NEON \ - || arm_fpu_arch == FPUTYPE_NEON_FP16)) +#define TARGET_VFPD32 (TARGET_VFP && arm_fpu_desc->regs == VFP_REG_D32) /* FPU supports VFPv3 instructions. */ -#define TARGET_VFP3 (arm_fp_model == ARM_FP_MODEL_VFP \ - && (arm_fpu_arch == FPUTYPE_VFP3D16 \ - || TARGET_VFPD32)) +#define TARGET_VFP3 (TARGET_VFP && arm_fpu_desc->rev >= 3) /* FPU supports NEON/VFP half-precision floating-point. */ -#define TARGET_NEON_FP16 (arm_fpu_arch == FPUTYPE_NEON_FP16) +#define TARGET_NEON_FP16 \ + (TARGET_VFP && arm_fpu_desc->neon && arm_fpu_desc->fp16) /* FPU supports Neon instructions. The setting of this macro gets revealed via __ARM_NEON__ so we add extra guards upon TARGET_32BIT and TARGET_HARD_FLOAT to ensure that NEON instructions are available. */ #define TARGET_NEON (TARGET_32BIT && TARGET_HARD_FLOAT \ - && arm_fp_model == ARM_FP_MODEL_VFP \ - && (arm_fpu_arch == FPUTYPE_NEON \ - || arm_fpu_arch == FPUTYPE_NEON_FP16)) + && TARGET_VFP && arm_fpu_desc->neon) /* "DSP" multiply instructions, eg. SMULxy. */ #define TARGET_DSP_MULTIPLY \ @@ -300,42 +296,25 @@ enum arm_fp_model ARM_FP_MODEL_VFP }; -extern enum arm_fp_model arm_fp_model; - -/* Which floating point hardware is available. Also update - fp_model_for_fpu in arm.c when adding entries to this list. */ -enum fputype +enum vfp_reg_type { - /* No FP hardware. */ - FPUTYPE_NONE, - /* Full FPA support. */ - FPUTYPE_FPA, - /* Emulated FPA hardware, Issue 2 emulator (no LFM/SFM). */ - FPUTYPE_FPA_EMU2, - /* Emulated FPA hardware, Issue 3 emulator. */ - FPUTYPE_FPA_EMU3, - /* Cirrus Maverick floating point co-processor. */ - FPUTYPE_MAVERICK, - /* VFP. */ - FPUTYPE_VFP, - /* VFPv3-D16. */ - FPUTYPE_VFP3D16, - /* VFPv3. */ - FPUTYPE_VFP3, - /* Neon. */ - FPUTYPE_NEON, - /* Neon with half-precision float extensions. */ - FPUTYPE_NEON_FP16 + VFP_REG_D16, + VFP_REG_D32, + VFP_REG_SINGLE }; -/* Recast the floating point class to be the floating point attribute. */ -#define arm_fpu_attr ((enum attr_fpu) arm_fpu_tune) - -/* What type of floating point to tune for */ -extern enum fputype arm_fpu_tune; - -/* What type of floating point instructions are available */ -extern enum fputype arm_fpu_arch; +extern const struct arm_fpu_desc +{ + const char *name; + enum arm_fp_model model; + int rev; + enum vfp_reg_type regs; + int neon; + int fp16; +} *arm_fpu_desc; + +/* Which floating point hardware to schedule for. */ +extern int arm_fpu_attr; enum float_abi_type { diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index e180c2f08f1..52edcbaa17b 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -160,7 +160,7 @@ ; Floating Point Unit. If we only have floating point emulation, then there ; is no point in scheduling the floating point insns. (Well, for best ; performance we should try and group them together). -(define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp,vfpv3d16,vfpv3,neon,neon_fp16" +(define_attr "fpu" "none,fpa,fpe2,fpe3,maverick,vfp" (const (symbol_ref "arm_fpu_attr"))) ; LENGTH of an instruction (in bytes) @@ -392,6 +392,9 @@ ; registers. (define_mode_iterator ANY64 [DI DF V8QI V4HI V2SI V2SF]) +;; The integer modes up to word size +(define_mode_iterator QHSI [QI HI SI]) + ;;--------------------------------------------------------------------------- ;; Predicates @@ -1914,7 +1917,16 @@ else /* TARGET_THUMB1 */ { if (GET_CODE (operands[2]) != CONST_INT) - operands[2] = force_reg (SImode, operands[2]); + { + rtx tmp = force_reg (SImode, operands[2]); + if (rtx_equal_p (operands[0], operands[1])) + operands[2] = tmp; + else + { + operands[2] = operands[1]; + operands[1] = tmp; + } + } else { int i; @@ -2623,7 +2635,16 @@ DONE; } else /* TARGET_THUMB1 */ - operands [2] = force_reg (SImode, operands [2]); + { + rtx tmp = force_reg (SImode, operands[2]); + if (rtx_equal_p (operands[0], operands[1])) + operands[2] = tmp; + else + { + operands[2] = operands[1]; + operands[1] = tmp; + } + } } " ) @@ -2731,12 +2752,29 @@ (define_expand "xorsi3" [(set (match_operand:SI 0 "s_register_operand" "") (xor:SI (match_operand:SI 1 "s_register_operand" "") - (match_operand:SI 2 "arm_rhs_operand" "")))] + (match_operand:SI 2 "reg_or_int_operand" "")))] "TARGET_EITHER" - "if (TARGET_THUMB1) - if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = force_reg (SImode, operands[2]); - " + "if (GET_CODE (operands[2]) == CONST_INT) + { + if (TARGET_32BIT) + { + arm_split_constant (XOR, SImode, NULL_RTX, + INTVAL (operands[2]), operands[0], operands[1], + optimize && can_create_pseudo_p ()); + DONE; + } + else /* TARGET_THUMB1 */ + { + rtx tmp = force_reg (SImode, operands[2]); + if (rtx_equal_p (operands[0], operands[1])) + operands[2] = tmp; + else + { + operands[2] = operands[1]; + operands[1] = tmp; + } + } + }" ) (define_insn "*arm_xorsi3" @@ -5813,6 +5851,11 @@ { rtx reg = gen_reg_rtx (SImode); + /* For thumb we want an unsigned immediate, then we are more likely + to be able to use a movs insn. */ + if (TARGET_THUMB) + operands[1] = GEN_INT (INTVAL (operands[1]) & 255); + emit_insn (gen_movsi (reg, operands[1])); operands[1] = gen_lowpart (QImode, reg); } @@ -6727,6 +6770,7 @@ (const_int 6) (const_int 8))))] ) + (define_insn "*movsi_cbranchsi4" [(set (pc) (if_then_else @@ -6790,6 +6834,45 @@ (const_int 10)))))] ) +(define_peephole2 + [(set (match_operand:SI 0 "low_register_operand" "") + (match_operand:SI 1 "low_register_operand" "")) + (set (pc) + (if_then_else (match_operator 2 "arm_comparison_operator" + [(match_dup 1) (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB1" + [(parallel + [(set (pc) + (if_then_else (match_op_dup 2 [(match_dup 1) (const_int 0)]) + (label_ref (match_dup 3)) + (pc))) + (set (match_dup 0) (match_dup 1))])] + "" +) + +;; Sigh! This variant shouldn't be needed, but combine often fails to +;; merge cases like this because the op1 is a hard register in +;; CLASS_LIKELY_SPILLED_P. +(define_peephole2 + [(set (match_operand:SI 0 "low_register_operand" "") + (match_operand:SI 1 "low_register_operand" "")) + (set (pc) + (if_then_else (match_operator 2 "arm_comparison_operator" + [(match_dup 0) (const_int 0)]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_THUMB1" + [(parallel + [(set (pc) + (if_then_else (match_op_dup 2 [(match_dup 1) (const_int 0)]) + (label_ref (match_dup 3)) + (pc))) + (set (match_dup 0) (match_dup 1))])] + "" +) + (define_insn "*negated_cbranchsi4" [(set (pc) (if_then_else @@ -8033,15 +8116,13 @@ if (!thumb1_cmp_operand (op3, SImode)) op3 = force_reg (SImode, op3); scratch = gen_reg_rtx (SImode); - emit_insn (gen_cstoresi_nltu_thumb1 (scratch, operands[2], op3)); - emit_insn (gen_negsi2 (operands[0], scratch)); + emit_insn (gen_cstoresi_ltu_thumb1 (operands[0], operands[2], op3)); break; case GTU: op3 = force_reg (SImode, operands[3]); scratch = gen_reg_rtx (SImode); - emit_insn (gen_cstoresi_nltu_thumb1 (scratch, op3, operands[2])); - emit_insn (gen_negsi2 (operands[0], scratch)); + emit_insn (gen_cstoresi_ltu_thumb1 (operands[0], op3, operands[2])); break; /* No good sequences for GT, LT. */ @@ -8125,6 +8206,7 @@ [(set_attr "length" "4")] ) +;; Used as part of the expansion of thumb ltu and gtu sequences (define_insn "cstoresi_nltu_thumb1" [(set (match_operand:SI 0 "s_register_operand" "=l,l") (neg:SI (ltu:SI (match_operand:SI 1 "s_register_operand" "l,*h") @@ -8134,6 +8216,20 @@ [(set_attr "length" "4")] ) +(define_insn_and_split "cstoresi_ltu_thumb1" + [(set (match_operand:SI 0 "s_register_operand" "=l,l") + (ltu:SI (match_operand:SI 1 "s_register_operand" "l,*h") + (match_operand:SI 2 "thumb1_cmp_operand" "lI*h,*r")))] + "TARGET_THUMB1" + "#" + "TARGET_THUMB1" + [(set (match_dup 3) + (neg:SI (ltu:SI (match_dup 1) (match_dup 2)))) + (set (match_dup 0) (neg:SI (match_dup 3)))] + "operands[3] = gen_reg_rtx (SImode);" + [(set_attr "length" "4")] +) + ;; Used as part of the expansion of thumb les sequence. (define_insn "thumb1_addsi3_addgeu" [(set (match_operand:SI 0 "s_register_operand" "=l") diff --git a/gcc/config/arm/arm_neon.h b/gcc/config/arm/arm_neon.h index faaaf7bca39..ccfc7426077 100644 --- a/gcc/config/arm/arm_neon.h +++ b/gcc/config/arm/arm_neon.h @@ -61,7 +61,7 @@ typedef __builtin_neon_uhi uint16x8_t __attribute__ ((__vector_size__ (16))); typedef __builtin_neon_usi uint32x4_t __attribute__ ((__vector_size__ (16))); typedef __builtin_neon_udi uint64x2_t __attribute__ ((__vector_size__ (16))); -typedef __builtin_neon_sf float32_t; +typedef float float32_t; typedef __builtin_neon_poly8 poly8_t; typedef __builtin_neon_poly16 poly16_t; @@ -5085,7 +5085,7 @@ vset_lane_s32 (int32_t __a, int32x2_t __b, const int __c) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vset_lane_f32 (float32_t __a, float32x2_t __b, const int __c) { - return (float32x2_t)__builtin_neon_vset_lanev2sf (__a, __b, __c); + return (float32x2_t)__builtin_neon_vset_lanev2sf ((__builtin_neon_sf) __a, __b, __c); } __extension__ static __inline uint8x8_t __attribute__ ((__always_inline__)) @@ -5151,7 +5151,7 @@ vsetq_lane_s32 (int32_t __a, int32x4_t __b, const int __c) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vsetq_lane_f32 (float32_t __a, float32x4_t __b, const int __c) { - return (float32x4_t)__builtin_neon_vset_lanev4sf (__a, __b, __c); + return (float32x4_t)__builtin_neon_vset_lanev4sf ((__builtin_neon_sf) __a, __b, __c); } __extension__ static __inline uint8x16_t __attribute__ ((__always_inline__)) @@ -5283,7 +5283,7 @@ vdup_n_s32 (int32_t __a) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vdup_n_f32 (float32_t __a) { - return (float32x2_t)__builtin_neon_vdup_nv2sf (__a); + return (float32x2_t)__builtin_neon_vdup_nv2sf ((__builtin_neon_sf) __a); } __extension__ static __inline uint8x8_t __attribute__ ((__always_inline__)) @@ -5349,7 +5349,7 @@ vdupq_n_s32 (int32_t __a) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vdupq_n_f32 (float32_t __a) { - return (float32x4_t)__builtin_neon_vdup_nv4sf (__a); + return (float32x4_t)__builtin_neon_vdup_nv4sf ((__builtin_neon_sf) __a); } __extension__ static __inline uint8x16_t __attribute__ ((__always_inline__)) @@ -5415,7 +5415,7 @@ vmov_n_s32 (int32_t __a) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vmov_n_f32 (float32_t __a) { - return (float32x2_t)__builtin_neon_vdup_nv2sf (__a); + return (float32x2_t)__builtin_neon_vdup_nv2sf ((__builtin_neon_sf) __a); } __extension__ static __inline uint8x8_t __attribute__ ((__always_inline__)) @@ -5481,7 +5481,7 @@ vmovq_n_s32 (int32_t __a) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vmovq_n_f32 (float32_t __a) { - return (float32x4_t)__builtin_neon_vdup_nv4sf (__a); + return (float32x4_t)__builtin_neon_vdup_nv4sf ((__builtin_neon_sf) __a); } __extension__ static __inline uint8x16_t __attribute__ ((__always_inline__)) @@ -6591,7 +6591,7 @@ vmul_n_s32 (int32x2_t __a, int32_t __b) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vmul_n_f32 (float32x2_t __a, float32_t __b) { - return (float32x2_t)__builtin_neon_vmul_nv2sf (__a, __b, 3); + return (float32x2_t)__builtin_neon_vmul_nv2sf (__a, (__builtin_neon_sf) __b, 3); } __extension__ static __inline uint16x4_t __attribute__ ((__always_inline__)) @@ -6621,7 +6621,7 @@ vmulq_n_s32 (int32x4_t __a, int32_t __b) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vmulq_n_f32 (float32x4_t __a, float32_t __b) { - return (float32x4_t)__builtin_neon_vmul_nv4sf (__a, __b, 3); + return (float32x4_t)__builtin_neon_vmul_nv4sf (__a, (__builtin_neon_sf) __b, 3); } __extension__ static __inline uint16x8_t __attribute__ ((__always_inline__)) @@ -6735,7 +6735,7 @@ vmla_n_s32 (int32x2_t __a, int32x2_t __b, int32_t __c) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vmla_n_f32 (float32x2_t __a, float32x2_t __b, float32_t __c) { - return (float32x2_t)__builtin_neon_vmla_nv2sf (__a, __b, __c, 3); + return (float32x2_t)__builtin_neon_vmla_nv2sf (__a, __b, (__builtin_neon_sf) __c, 3); } __extension__ static __inline uint16x4_t __attribute__ ((__always_inline__)) @@ -6765,7 +6765,7 @@ vmlaq_n_s32 (int32x4_t __a, int32x4_t __b, int32_t __c) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vmlaq_n_f32 (float32x4_t __a, float32x4_t __b, float32_t __c) { - return (float32x4_t)__builtin_neon_vmla_nv4sf (__a, __b, __c, 3); + return (float32x4_t)__builtin_neon_vmla_nv4sf (__a, __b, (__builtin_neon_sf) __c, 3); } __extension__ static __inline uint16x8_t __attribute__ ((__always_inline__)) @@ -6831,7 +6831,7 @@ vmls_n_s32 (int32x2_t __a, int32x2_t __b, int32_t __c) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vmls_n_f32 (float32x2_t __a, float32x2_t __b, float32_t __c) { - return (float32x2_t)__builtin_neon_vmls_nv2sf (__a, __b, __c, 3); + return (float32x2_t)__builtin_neon_vmls_nv2sf (__a, __b, (__builtin_neon_sf) __c, 3); } __extension__ static __inline uint16x4_t __attribute__ ((__always_inline__)) @@ -6861,7 +6861,7 @@ vmlsq_n_s32 (int32x4_t __a, int32x4_t __b, int32_t __c) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vmlsq_n_f32 (float32x4_t __a, float32x4_t __b, float32_t __c) { - return (float32x4_t)__builtin_neon_vmls_nv4sf (__a, __b, __c, 3); + return (float32x4_t)__builtin_neon_vmls_nv4sf (__a, __b, (__builtin_neon_sf) __c, 3); } __extension__ static __inline uint16x8_t __attribute__ ((__always_inline__)) @@ -7851,7 +7851,7 @@ vld1_s64 (const int64_t * __a) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vld1_f32 (const float32_t * __a) { - return (float32x2_t)__builtin_neon_vld1v2sf (__a); + return (float32x2_t)__builtin_neon_vld1v2sf ((const __builtin_neon_sf *) __a); } __extension__ static __inline uint8x8_t __attribute__ ((__always_inline__)) @@ -7917,7 +7917,7 @@ vld1q_s64 (const int64_t * __a) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vld1q_f32 (const float32_t * __a) { - return (float32x4_t)__builtin_neon_vld1v4sf (__a); + return (float32x4_t)__builtin_neon_vld1v4sf ((const __builtin_neon_sf *) __a); } __extension__ static __inline uint8x16_t __attribute__ ((__always_inline__)) @@ -7977,7 +7977,7 @@ vld1_lane_s32 (const int32_t * __a, int32x2_t __b, const int __c) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vld1_lane_f32 (const float32_t * __a, float32x2_t __b, const int __c) { - return (float32x2_t)__builtin_neon_vld1_lanev2sf (__a, __b, __c); + return (float32x2_t)__builtin_neon_vld1_lanev2sf ((const __builtin_neon_sf *) __a, __b, __c); } __extension__ static __inline uint8x8_t __attribute__ ((__always_inline__)) @@ -8043,7 +8043,7 @@ vld1q_lane_s32 (const int32_t * __a, int32x4_t __b, const int __c) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vld1q_lane_f32 (const float32_t * __a, float32x4_t __b, const int __c) { - return (float32x4_t)__builtin_neon_vld1_lanev4sf (__a, __b, __c); + return (float32x4_t)__builtin_neon_vld1_lanev4sf ((const __builtin_neon_sf *) __a, __b, __c); } __extension__ static __inline uint8x16_t __attribute__ ((__always_inline__)) @@ -8109,7 +8109,7 @@ vld1_dup_s32 (const int32_t * __a) __extension__ static __inline float32x2_t __attribute__ ((__always_inline__)) vld1_dup_f32 (const float32_t * __a) { - return (float32x2_t)__builtin_neon_vld1_dupv2sf (__a); + return (float32x2_t)__builtin_neon_vld1_dupv2sf ((const __builtin_neon_sf *) __a); } __extension__ static __inline uint8x8_t __attribute__ ((__always_inline__)) @@ -8175,7 +8175,7 @@ vld1q_dup_s32 (const int32_t * __a) __extension__ static __inline float32x4_t __attribute__ ((__always_inline__)) vld1q_dup_f32 (const float32_t * __a) { - return (float32x4_t)__builtin_neon_vld1_dupv4sf (__a); + return (float32x4_t)__builtin_neon_vld1_dupv4sf ((const __builtin_neon_sf *) __a); } __extension__ static __inline uint8x16_t __attribute__ ((__always_inline__)) @@ -8247,7 +8247,7 @@ vst1_s64 (int64_t * __a, int64x1_t __b) __extension__ static __inline void __attribute__ ((__always_inline__)) vst1_f32 (float32_t * __a, float32x2_t __b) { - __builtin_neon_vst1v2sf (__a, __b); + __builtin_neon_vst1v2sf ((__builtin_neon_sf *) __a, __b); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -8313,7 +8313,7 @@ vst1q_s64 (int64_t * __a, int64x2_t __b) __extension__ static __inline void __attribute__ ((__always_inline__)) vst1q_f32 (float32_t * __a, float32x4_t __b) { - __builtin_neon_vst1v4sf (__a, __b); + __builtin_neon_vst1v4sf ((__builtin_neon_sf *) __a, __b); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -8373,7 +8373,7 @@ vst1_lane_s32 (int32_t * __a, int32x2_t __b, const int __c) __extension__ static __inline void __attribute__ ((__always_inline__)) vst1_lane_f32 (float32_t * __a, float32x2_t __b, const int __c) { - __builtin_neon_vst1_lanev2sf (__a, __b, __c); + __builtin_neon_vst1_lanev2sf ((__builtin_neon_sf *) __a, __b, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -8439,7 +8439,7 @@ vst1q_lane_s32 (int32_t * __a, int32x4_t __b, const int __c) __extension__ static __inline void __attribute__ ((__always_inline__)) vst1q_lane_f32 (float32_t * __a, float32x4_t __b, const int __c) { - __builtin_neon_vst1_lanev4sf (__a, __b, __c); + __builtin_neon_vst1_lanev4sf ((__builtin_neon_sf *) __a, __b, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -8512,7 +8512,7 @@ __extension__ static __inline float32x2x2_t __attribute__ ((__always_inline__)) vld2_f32 (const float32_t * __a) { union { float32x2x2_t __i; __builtin_neon_ti __o; } __rv; - __rv.__o = __builtin_neon_vld2v2sf (__a); + __rv.__o = __builtin_neon_vld2v2sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -8600,7 +8600,7 @@ __extension__ static __inline float32x4x2_t __attribute__ ((__always_inline__)) vld2q_f32 (const float32_t * __a) { union { float32x4x2_t __i; __builtin_neon_oi __o; } __rv; - __rv.__o = __builtin_neon_vld2v4sf (__a); + __rv.__o = __builtin_neon_vld2v4sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -8676,7 +8676,7 @@ vld2_lane_f32 (const float32_t * __a, float32x2x2_t __b, const int __c) { union { float32x2x2_t __i; __builtin_neon_ti __o; } __bu = { __b }; union { float32x2x2_t __i; __builtin_neon_ti __o; } __rv; - __rv.__o = __builtin_neon_vld2_lanev2sf (__a, __bu.__o, __c); + __rv.__o = __builtin_neon_vld2_lanev2sf ((const __builtin_neon_sf *) __a, __bu.__o, __c); return __rv.__i; } @@ -8748,7 +8748,7 @@ vld2q_lane_f32 (const float32_t * __a, float32x4x2_t __b, const int __c) { union { float32x4x2_t __i; __builtin_neon_oi __o; } __bu = { __b }; union { float32x4x2_t __i; __builtin_neon_oi __o; } __rv; - __rv.__o = __builtin_neon_vld2_lanev4sf (__a, __bu.__o, __c); + __rv.__o = __builtin_neon_vld2_lanev4sf ((const __builtin_neon_sf *) __a, __bu.__o, __c); return __rv.__i; } @@ -8807,7 +8807,7 @@ __extension__ static __inline float32x2x2_t __attribute__ ((__always_inline__)) vld2_dup_f32 (const float32_t * __a) { union { float32x2x2_t __i; __builtin_neon_ti __o; } __rv; - __rv.__o = __builtin_neon_vld2_dupv2sf (__a); + __rv.__o = __builtin_neon_vld2_dupv2sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -8892,7 +8892,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst2_f32 (float32_t * __a, float32x2x2_t __b) { union { float32x2x2_t __i; __builtin_neon_ti __o; } __bu = { __b }; - __builtin_neon_vst2v2sf (__a, __bu.__o); + __builtin_neon_vst2v2sf ((__builtin_neon_sf *) __a, __bu.__o); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -8969,7 +8969,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst2q_f32 (float32_t * __a, float32x4x2_t __b) { union { float32x4x2_t __i; __builtin_neon_oi __o; } __bu = { __b }; - __builtin_neon_vst2v4sf (__a, __bu.__o); + __builtin_neon_vst2v4sf ((__builtin_neon_sf *) __a, __bu.__o); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -9032,7 +9032,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst2_lane_f32 (float32_t * __a, float32x2x2_t __b, const int __c) { union { float32x2x2_t __i; __builtin_neon_ti __o; } __bu = { __b }; - __builtin_neon_vst2_lanev2sf (__a, __bu.__o, __c); + __builtin_neon_vst2_lanev2sf ((__builtin_neon_sf *) __a, __bu.__o, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -9088,7 +9088,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst2q_lane_f32 (float32_t * __a, float32x4x2_t __b, const int __c) { union { float32x4x2_t __i; __builtin_neon_oi __o; } __bu = { __b }; - __builtin_neon_vst2_lanev4sf (__a, __bu.__o, __c); + __builtin_neon_vst2_lanev4sf ((__builtin_neon_sf *) __a, __bu.__o, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -9140,7 +9140,7 @@ __extension__ static __inline float32x2x3_t __attribute__ ((__always_inline__)) vld3_f32 (const float32_t * __a) { union { float32x2x3_t __i; __builtin_neon_ei __o; } __rv; - __rv.__o = __builtin_neon_vld3v2sf (__a); + __rv.__o = __builtin_neon_vld3v2sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -9228,7 +9228,7 @@ __extension__ static __inline float32x4x3_t __attribute__ ((__always_inline__)) vld3q_f32 (const float32_t * __a) { union { float32x4x3_t __i; __builtin_neon_ci __o; } __rv; - __rv.__o = __builtin_neon_vld3v4sf (__a); + __rv.__o = __builtin_neon_vld3v4sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -9304,7 +9304,7 @@ vld3_lane_f32 (const float32_t * __a, float32x2x3_t __b, const int __c) { union { float32x2x3_t __i; __builtin_neon_ei __o; } __bu = { __b }; union { float32x2x3_t __i; __builtin_neon_ei __o; } __rv; - __rv.__o = __builtin_neon_vld3_lanev2sf (__a, __bu.__o, __c); + __rv.__o = __builtin_neon_vld3_lanev2sf ((const __builtin_neon_sf *) __a, __bu.__o, __c); return __rv.__i; } @@ -9376,7 +9376,7 @@ vld3q_lane_f32 (const float32_t * __a, float32x4x3_t __b, const int __c) { union { float32x4x3_t __i; __builtin_neon_ci __o; } __bu = { __b }; union { float32x4x3_t __i; __builtin_neon_ci __o; } __rv; - __rv.__o = __builtin_neon_vld3_lanev4sf (__a, __bu.__o, __c); + __rv.__o = __builtin_neon_vld3_lanev4sf ((const __builtin_neon_sf *) __a, __bu.__o, __c); return __rv.__i; } @@ -9435,7 +9435,7 @@ __extension__ static __inline float32x2x3_t __attribute__ ((__always_inline__)) vld3_dup_f32 (const float32_t * __a) { union { float32x2x3_t __i; __builtin_neon_ei __o; } __rv; - __rv.__o = __builtin_neon_vld3_dupv2sf (__a); + __rv.__o = __builtin_neon_vld3_dupv2sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -9520,7 +9520,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst3_f32 (float32_t * __a, float32x2x3_t __b) { union { float32x2x3_t __i; __builtin_neon_ei __o; } __bu = { __b }; - __builtin_neon_vst3v2sf (__a, __bu.__o); + __builtin_neon_vst3v2sf ((__builtin_neon_sf *) __a, __bu.__o); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -9597,7 +9597,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst3q_f32 (float32_t * __a, float32x4x3_t __b) { union { float32x4x3_t __i; __builtin_neon_ci __o; } __bu = { __b }; - __builtin_neon_vst3v4sf (__a, __bu.__o); + __builtin_neon_vst3v4sf ((__builtin_neon_sf *) __a, __bu.__o); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -9660,7 +9660,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst3_lane_f32 (float32_t * __a, float32x2x3_t __b, const int __c) { union { float32x2x3_t __i; __builtin_neon_ei __o; } __bu = { __b }; - __builtin_neon_vst3_lanev2sf (__a, __bu.__o, __c); + __builtin_neon_vst3_lanev2sf ((__builtin_neon_sf *) __a, __bu.__o, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -9716,7 +9716,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst3q_lane_f32 (float32_t * __a, float32x4x3_t __b, const int __c) { union { float32x4x3_t __i; __builtin_neon_ci __o; } __bu = { __b }; - __builtin_neon_vst3_lanev4sf (__a, __bu.__o, __c); + __builtin_neon_vst3_lanev4sf ((__builtin_neon_sf *) __a, __bu.__o, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -9768,7 +9768,7 @@ __extension__ static __inline float32x2x4_t __attribute__ ((__always_inline__)) vld4_f32 (const float32_t * __a) { union { float32x2x4_t __i; __builtin_neon_oi __o; } __rv; - __rv.__o = __builtin_neon_vld4v2sf (__a); + __rv.__o = __builtin_neon_vld4v2sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -9856,7 +9856,7 @@ __extension__ static __inline float32x4x4_t __attribute__ ((__always_inline__)) vld4q_f32 (const float32_t * __a) { union { float32x4x4_t __i; __builtin_neon_xi __o; } __rv; - __rv.__o = __builtin_neon_vld4v4sf (__a); + __rv.__o = __builtin_neon_vld4v4sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -9932,7 +9932,7 @@ vld4_lane_f32 (const float32_t * __a, float32x2x4_t __b, const int __c) { union { float32x2x4_t __i; __builtin_neon_oi __o; } __bu = { __b }; union { float32x2x4_t __i; __builtin_neon_oi __o; } __rv; - __rv.__o = __builtin_neon_vld4_lanev2sf (__a, __bu.__o, __c); + __rv.__o = __builtin_neon_vld4_lanev2sf ((const __builtin_neon_sf *) __a, __bu.__o, __c); return __rv.__i; } @@ -10004,7 +10004,7 @@ vld4q_lane_f32 (const float32_t * __a, float32x4x4_t __b, const int __c) { union { float32x4x4_t __i; __builtin_neon_xi __o; } __bu = { __b }; union { float32x4x4_t __i; __builtin_neon_xi __o; } __rv; - __rv.__o = __builtin_neon_vld4_lanev4sf (__a, __bu.__o, __c); + __rv.__o = __builtin_neon_vld4_lanev4sf ((const __builtin_neon_sf *) __a, __bu.__o, __c); return __rv.__i; } @@ -10063,7 +10063,7 @@ __extension__ static __inline float32x2x4_t __attribute__ ((__always_inline__)) vld4_dup_f32 (const float32_t * __a) { union { float32x2x4_t __i; __builtin_neon_oi __o; } __rv; - __rv.__o = __builtin_neon_vld4_dupv2sf (__a); + __rv.__o = __builtin_neon_vld4_dupv2sf ((const __builtin_neon_sf *) __a); return __rv.__i; } @@ -10148,7 +10148,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst4_f32 (float32_t * __a, float32x2x4_t __b) { union { float32x2x4_t __i; __builtin_neon_oi __o; } __bu = { __b }; - __builtin_neon_vst4v2sf (__a, __bu.__o); + __builtin_neon_vst4v2sf ((__builtin_neon_sf *) __a, __bu.__o); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -10225,7 +10225,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst4q_f32 (float32_t * __a, float32x4x4_t __b) { union { float32x4x4_t __i; __builtin_neon_xi __o; } __bu = { __b }; - __builtin_neon_vst4v4sf (__a, __bu.__o); + __builtin_neon_vst4v4sf ((__builtin_neon_sf *) __a, __bu.__o); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -10288,7 +10288,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst4_lane_f32 (float32_t * __a, float32x2x4_t __b, const int __c) { union { float32x2x4_t __i; __builtin_neon_oi __o; } __bu = { __b }; - __builtin_neon_vst4_lanev2sf (__a, __bu.__o, __c); + __builtin_neon_vst4_lanev2sf ((__builtin_neon_sf *) __a, __bu.__o, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) @@ -10344,7 +10344,7 @@ __extension__ static __inline void __attribute__ ((__always_inline__)) vst4q_lane_f32 (float32_t * __a, float32x4x4_t __b, const int __c) { union { float32x4x4_t __i; __builtin_neon_xi __o; } __bu = { __b }; - __builtin_neon_vst4_lanev4sf (__a, __bu.__o, __c); + __builtin_neon_vst4_lanev4sf ((__builtin_neon_sf *) __a, __bu.__o, __c); } __extension__ static __inline void __attribute__ ((__always_inline__)) diff --git a/gcc/config/arm/bpabi.h b/gcc/config/arm/bpabi.h index bc0c62f401e..ba206022b75 100644 --- a/gcc/config/arm/bpabi.h +++ b/gcc/config/arm/bpabi.h @@ -30,7 +30,7 @@ /* Section 4.1 of the AAPCS requires the use of VFP format. */ #undef FPUTYPE_DEFAULT -#define FPUTYPE_DEFAULT FPUTYPE_VFP +#define FPUTYPE_DEFAULT "vfp" /* TARGET_BIG_ENDIAN_DEFAULT is set in config.gcc for big endian configurations. */ @@ -53,6 +53,8 @@ #define TARGET_FIX_V4BX_SPEC " %{mcpu=arm8|mcpu=arm810|mcpu=strongarm*|march=armv4:--fix-v4bx}" +#define BE8_LINK_SPEC " %{mbig-endian:%{march=armv7-a|mcpu=cortex-a8|mcpu=cortex-a9:%{!r:--be8}}}" + /* Tell the assembler to build BPABI binaries. */ #undef SUBTARGET_EXTRA_ASM_SPEC #define SUBTARGET_EXTRA_ASM_SPEC "%{mabi=apcs-gnu|mabi=atpcs:-meabi=gnu;:-meabi=5}" TARGET_FIX_V4BX_SPEC @@ -65,7 +67,7 @@ #define BPABI_LINK_SPEC \ "%{mbig-endian:-EB} %{mlittle-endian:-EL} " \ "%{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic} " \ - "-X" SUBTARGET_EXTRA_LINK_SPEC TARGET_FIX_V4BX_SPEC + "-X" SUBTARGET_EXTRA_LINK_SPEC TARGET_FIX_V4BX_SPEC BE8_LINK_SPEC #undef LINK_SPEC #define LINK_SPEC BPABI_LINK_SPEC diff --git a/gcc/config/arm/cortex-a9.md b/gcc/config/arm/cortex-a9.md index 121fd2da747..d1ad7cba767 100644 --- a/gcc/config/arm/cortex-a9.md +++ b/gcc/config/arm/cortex-a9.md @@ -1,6 +1,8 @@ -;; ARM Cortex-A9 VFP pipeline description -;; Copyright (C) 2008 Free Software Foundation, Inc. -;; Written by CodeSourcery. +;; ARM Cortex-A9 pipeline description +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Originally written by CodeSourcery for VFP. +;; +;; Integer core pipeline description contributed by ARM Ltd. ;; ;; This file is part of GCC. ;; @@ -20,9 +22,181 @@ (define_automaton "cortex_a9") -;; FIXME: We model a single pipeline for all instructions. -;; Is dual-issue possible, and do we have other pipelines? -(define_cpu_unit "cortex_a9_vfp" "cortex_a9") +;; The Cortex-A9 integer core is modelled as a dual issue pipeline that has +;; the following components. +;; 1. 1 Load Store Pipeline. +;; 2. P0 / main pipeline for data processing instructions. +;; 3. P1 / Dual pipeline for Data processing instructions. +;; 4. MAC pipeline for multiply as well as multiply +;; and accumulate instructions. +;; 5. 1 VFP / Neon pipeline. +;; The Load/Store and VFP/Neon pipeline are multiplexed. +;; The P0 / main pipeline and M1 stage of the MAC pipeline are +;; multiplexed. +;; The P1 / dual pipeline and M2 stage of the MAC pipeline are +;; multiplexed. +;; There are only 4 register read ports and hence at any point of +;; time we can't have issue down the E1 and the E2 ports unless +;; of course there are bypass paths that get exercised. +;; Both P0 and P1 have 2 stages E1 and E2. +;; Data processing instructions issue to E1 or E2 depending on +;; whether they have an early shift or not. + + +(define_cpu_unit "cortex_a9_vfp, cortex_a9_ls" "cortex_a9") +(define_cpu_unit "cortex_a9_p0_e1, cortex_a9_p0_e2" "cortex_a9") +(define_cpu_unit "cortex_a9_p1_e1, cortex_a9_p1_e2" "cortex_a9") +(define_cpu_unit "cortex_a9_p0_wb, cortex_a9_p1_wb" "cortex_a9") +(define_cpu_unit "cortex_a9_mac_m1, cortex_a9_mac_m2" "cortex_a9") +(define_cpu_unit "cortex_a9_branch, cortex_a9_issue_branch" "cortex_a9") + +(define_reservation "cortex_a9_p0_default" "cortex_a9_p0_e2, cortex_a9_p0_wb") +(define_reservation "cortex_a9_p1_default" "cortex_a9_p1_e2, cortex_a9_p1_wb") +(define_reservation "cortex_a9_p0_shift" "cortex_a9_p0_e1, cortex_a9_p0_default") +(define_reservation "cortex_a9_p1_shift" "cortex_a9_p1_e1, cortex_a9_p1_default") + +(define_reservation "cortex_a9_multcycle1" + "cortex_a9_p0_e2 + cortex_a9_mac_m1 + cortex_a9_mac_m2 + \ +cortex_a9_p1_e2 + cortex_a9_p0_e1 + cortex_a9_p1_e1") + +(define_reservation "cortex_a9_mult16" + "cortex_a9_mac_m1, cortex_a9_mac_m2, cortex_a9_p0_wb") +(define_reservation "cortex_a9_mac16" + "cortex_a9_multcycle1, cortex_a9_mac_m2, cortex_a9_p0_wb") +(define_reservation "cortex_a9_mult" + "cortex_a9_mac_m1*2, cortex_a9_mac_m2, cortex_a9_p0_wb") +(define_reservation "cortex_a9_mac" + "cortex_a9_multcycle1*2 ,cortex_a9_mac_m2, cortex_a9_p0_wb") + + +;; Issue at the same time along the load store pipeline and +;; the VFP / Neon pipeline is not possible. +;; FIXME:: At some point we need to model the issue +;; of the load store and the vfp being shared rather than anything else. + +(exclusion_set "cortex_a9_ls" "cortex_a9_vfp") + + +;; Default data processing instruction without any shift +;; The only exception to this is the mov instruction +;; which can go down E2 without any problem. +(define_insn_reservation "cortex_a9_dp" 2 + (and (eq_attr "tune" "cortexa9") + (ior (eq_attr "type" "alu") + (and (eq_attr "type" "alu_shift_reg, alu_shift") + (eq_attr "insn" "mov")))) + "cortex_a9_p0_default|cortex_a9_p1_default") + +;; An instruction using the shifter will go down E1. +(define_insn_reservation "cortex_a9_dp_shift" 3 + (and (eq_attr "tune" "cortexa9") + (and (eq_attr "type" "alu_shift_reg, alu_shift") + (not (eq_attr "insn" "mov")))) + "cortex_a9_p0_shift | cortex_a9_p1_shift") + +;; Loads have a latency of 4 cycles. +;; We don't model autoincrement instructions. These +;; instructions use the load store pipeline and 1 of +;; the E2 units to write back the result of the increment. + +(define_insn_reservation "cortex_a9_load1_2" 4 + (and (eq_attr "tune" "cortexa9") + (eq_attr "type" "load1, load2, load_byte")) + "cortex_a9_ls") + +;; Loads multiples and store multiples can't be issued for 2 cycles in a +;; row. The description below assumes that addresses are 64 bit aligned. +;; If not, there is an extra cycle latency which is not modelled. + +;; FIXME:: This bit might need to be reworked when we get to +;; tuning for the VFP because strictly speaking the ldm +;; is sent to the LSU unit as is and there is only an +;; issue restriction between the LSU and the VFP/ Neon unit. + +(define_insn_reservation "cortex_a9_load3_4" 5 + (and (eq_attr "tune" "cortexa9") + (eq_attr "type" "load3, load4")) + "cortex_a9_ls, cortex_a9_ls") + +(define_insn_reservation "cortex_a9_store1_2" 0 + (and (eq_attr "tune" "cortexa9") + (eq_attr "type" "store1, store2")) + "cortex_a9_ls") + +;; Almost all our store multiples use an auto-increment +;; form. Don't issue back to back load and store multiples +;; because the load store unit will stall. +(define_insn_reservation "cortex_a9_store3_4" 0 + (and (eq_attr "tune" "cortexa9") + (eq_attr "type" "store3, store4")) + "cortex_a9_ls+(cortex_a9_p0_default | cortex_a9_p1_default), cortex_a9_ls") + +;; We get 16*16 multiply / mac results in 3 cycles. +(define_insn_reservation "cortex_a9_mult16" 3 + (and (eq_attr "tune" "cortexa9") + (eq_attr "insn" "smulxy")) + "cortex_a9_mult16") + +;; The 16*16 mac is slightly different that it +;; reserves M1 and M2 in the same cycle. +(define_insn_reservation "cortex_a9_mac16" 3 + (and (eq_attr "tune" "cortexa9") + (eq_attr "insn" "smlaxy")) + "cortex_a9_mac16") + + +(define_insn_reservation "cortex_a9_multiply" 4 + (and (eq_attr "tune" "cortexa9") + (eq_attr "insn" "mul")) + "cortex_a9_mult") + +(define_insn_reservation "cortex_a9_mac" 4 + (and (eq_attr "tune" "cortexa9") + (eq_attr "insn" "mla")) + "cortex_a9_mac") + +;; An instruction with a result in E2 can be forwarded +;; to E2 or E1 or M1 or the load store unit in the next cycle. + +(define_bypass 1 "cortex_a9_dp" + "cortex_a9_dp_shift, cortex_a9_multiply, + cortex_a9_load1_2, cortex_a9_dp, cortex_a9_store1_2, + cortex_a9_mult16, cortex_a9_mac16, cortex_a9_mac, cortex_a9_store3_4, cortex_a9_load3_4") + +(define_bypass 2 "cortex_a9_dp_shift" + "cortex_a9_dp_shift, cortex_a9_multiply, + cortex_a9_load1_2, cortex_a9_dp, cortex_a9_store1_2, + cortex_a9_mult16, cortex_a9_mac16, cortex_a9_mac, cortex_a9_store3_4, cortex_a9_load3_4") + +;; An instruction in the load store pipeline can provide +;; read access to a DP instruction in the P0 default pipeline +;; before the writeback stage. + +(define_bypass 3 "cortex_a9_load1_2" "cortex_a9_dp, cortex_a9_load1_2, +cortex_a9_store3_4, cortex_a9_store1_2") + +(define_bypass 4 "cortex_a9_load3_4" "cortex_a9_dp, cortex_a9_load1_2, +cortex_a9_store3_4, cortex_a9_store1_2, cortex_a9_load3_4") + +;; Calls and branches. + +;; Branch instructions + +(define_insn_reservation "cortex_a9_branch" 0 + (and (eq_attr "tune" "cortexa9") + (eq_attr "type" "branch")) + "cortex_a9_branch") + +;; Call latencies are essentially 0 but make sure +;; dual issue doesn't happen i.e the next instruction +;; starts at the next cycle. +(define_insn_reservation "cortex_a9_call" 0 + (and (eq_attr "tune" "cortexa9") + (eq_attr "type" "call")) + "cortex_a9_issue_branch + cortex_a9_multcycle1 + cortex_a9_ls + cortex_a9_vfp") + + +;; Pipelining for VFP instructions. (define_insn_reservation "cortex_a9_ffarith" 1 (and (eq_attr "tune" "cortexa9") diff --git a/gcc/config/arm/fpa.md b/gcc/config/arm/fpa.md index fcd92b002d7..515de43d28b 100644 --- a/gcc/config/arm/fpa.md +++ b/gcc/config/arm/fpa.md @@ -599,10 +599,10 @@ { default: case 0: return \"mvf%?e\\t%0, %1\"; - case 1: if (arm_fpu_arch == FPUTYPE_FPA_EMU2) + case 1: if (TARGET_FPA_EMU2) return \"ldf%?e\\t%0, %1\"; return \"lfm%?\\t%0, 1, %1\"; - case 2: if (arm_fpu_arch == FPUTYPE_FPA_EMU2) + case 2: if (TARGET_FPA_EMU2) return \"stf%?e\\t%1, %0\"; return \"sfm%?\\t%1, 1, %0\"; } diff --git a/gcc/config/arm/linux-eabi.h b/gcc/config/arm/linux-eabi.h index 780a504add2..fce1ed165d3 100644 --- a/gcc/config/arm/linux-eabi.h +++ b/gcc/config/arm/linux-eabi.h @@ -66,7 +66,7 @@ /* At this point, bpabi.h will have clobbered LINK_SPEC. We want to use the GNU/Linux version, not the generic BPABI version. */ #undef LINK_SPEC -#define LINK_SPEC LINUX_TARGET_LINK_SPEC +#define LINK_SPEC LINUX_TARGET_LINK_SPEC BE8_LINK_SPEC /* Use the default LIBGCC_SPEC, not the version in linux-elf.h, as we do not use -lfloat. */ diff --git a/gcc/config/arm/linux-elf.h b/gcc/config/arm/linux-elf.h index 07455ee87fd..9fdca414e8e 100644 --- a/gcc/config/arm/linux-elf.h +++ b/gcc/config/arm/linux-elf.h @@ -98,7 +98,7 @@ /* NWFPE always understands FPA instructions. */ #undef FPUTYPE_DEFAULT -#define FPUTYPE_DEFAULT FPUTYPE_FPA_EMU3 +#define FPUTYPE_DEFAULT "fpe3" /* Call the function profiler with a given profile label. */ #undef ARM_FUNCTION_PROFILER diff --git a/gcc/config/arm/neon-gen.ml b/gcc/config/arm/neon-gen.ml index 9c8e2a89b86..112c8be6e3b 100644 --- a/gcc/config/arm/neon-gen.ml +++ b/gcc/config/arm/neon-gen.ml @@ -122,6 +122,7 @@ let rec signed_ctype = function | T_uint16 | T_int16 -> T_intHI | T_uint32 | T_int32 -> T_intSI | T_uint64 | T_int64 -> T_intDI + | T_float32 -> T_floatSF | T_poly8 -> T_intQI | T_poly16 -> T_intHI | T_arrayof (n, elt) -> T_arrayof (n, signed_ctype elt) @@ -320,7 +321,7 @@ let deftypes () = typeinfo; Format.print_newline (); (* Extra types not in . *) - Format.printf "typedef __builtin_neon_sf float32_t;\n"; + Format.printf "typedef float float32_t;\n"; Format.printf "typedef __builtin_neon_poly8 poly8_t;\n"; Format.printf "typedef __builtin_neon_poly16 poly16_t;\n" diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md index 85bc3eed100..7d1ef111339 100644 --- a/gcc/config/arm/neon.md +++ b/gcc/config/arm/neon.md @@ -3655,7 +3655,8 @@ UNSPEC_VSHLL_N))] "TARGET_NEON" { - neon_const_bounds (operands[2], 0, neon_element_bits (mode)); + /* The boundaries are: 0 < imm <= size. */ + neon_const_bounds (operands[2], 0, neon_element_bits (mode) + 1); return "vshll.%T3%#\t%q0, %P1, %2"; } [(set_attr "neon_type" "neon_shift_1")] diff --git a/gcc/config/arm/neon.ml b/gcc/config/arm/neon.ml index 10393b33ebc..114097d22a7 100644 --- a/gcc/config/arm/neon.ml +++ b/gcc/config/arm/neon.ml @@ -50,7 +50,7 @@ type vectype = T_int8x8 | T_int8x16 | T_ptrto of vectype | T_const of vectype | T_void | T_intQI | T_intHI | T_intSI - | T_intDI + | T_intDI | T_floatSF (* The meanings of the following are: TImode : "Tetra", two registers (four words). @@ -1693,6 +1693,7 @@ let string_of_vectype vt = | T_intHI -> "__builtin_neon_hi" | T_intSI -> "__builtin_neon_si" | T_intDI -> "__builtin_neon_di" + | T_floatSF -> "__builtin_neon_sf" | T_arrayof (num, base) -> let basename = name (fun x -> x) base in affix (Printf.sprintf "%sx%d" basename num) diff --git a/gcc/config/arm/netbsd-elf.h b/gcc/config/arm/netbsd-elf.h index 4c06fa1cb3b..9cf186b338d 100644 --- a/gcc/config/arm/netbsd-elf.h +++ b/gcc/config/arm/netbsd-elf.h @@ -153,5 +153,5 @@ do \ while (0) #undef FPUTYPE_DEFAULT -#define FPUTYPE_DEFAULT FPUTYPE_VFP +#define FPUTYPE_DEFAULT "vfp" diff --git a/gcc/config/arm/thumb2.md b/gcc/config/arm/thumb2.md index 884d58c7677..82f75f9b733 100644 --- a/gcc/config/arm/thumb2.md +++ b/gcc/config/arm/thumb2.md @@ -1156,8 +1156,8 @@ ;; 16-bit load immediate (define_peephole2 - [(set (match_operand:SI 0 "low_register_operand" "") - (match_operand:SI 1 "const_int_operand" ""))] + [(set (match_operand:QHSI 0 "low_register_operand" "") + (match_operand:QHSI 1 "const_int_operand" ""))] "TARGET_THUMB2 && peep2_regno_dead_p(0, CC_REGNUM) && (unsigned HOST_WIDE_INT) INTVAL(operands[1]) < 256" @@ -1168,9 +1168,9 @@ "" ) -(define_insn "*thumb2_movsi_shortim" - [(set (match_operand:SI 0 "low_register_operand" "=l") - (match_operand:SI 1 "const_int_operand" "I")) +(define_insn "*thumb2_mov_shortim" + [(set (match_operand:QHSI 0 "low_register_operand" "=l") + (match_operand:QHSI 1 "const_int_operand" "I")) (clobber (reg:CC CC_REGNUM))] "TARGET_THUMB2 && reload_completed" "mov%!\t%0, %1" diff --git a/gcc/config/arm/unwind-arm.c b/gcc/config/arm/unwind-arm.c index 4eb18215f17..2c6e004890e 100644 --- a/gcc/config/arm/unwind-arm.c +++ b/gcc/config/arm/unwind-arm.c @@ -1000,7 +1000,6 @@ __gnu_Unwind_Backtrace(_Unwind_Trace_Fn trace, void * trace_argument, while (code != _URC_END_OF_STACK && code != _URC_FAILURE); - finish: restore_non_core_regs (&saved_vrs); return code; } diff --git a/gcc/config/arm/vxworks.h b/gcc/config/arm/vxworks.h index 8879fedb7d7..aa7e197bc5d 100644 --- a/gcc/config/arm/vxworks.h +++ b/gcc/config/arm/vxworks.h @@ -97,7 +97,7 @@ along with GCC; see the file COPYING3. If not see /* There is no default multilib. */ #undef MULTILIB_DEFAULTS -#define FPUTYPE_DEFAULT FPUTYPE_VFP +#define FPUTYPE_DEFAULT "vfp" #undef FUNCTION_PROFILER #define FUNCTION_PROFILER VXWORKS_FUNCTION_PROFILER diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 76df476f4c4..cb2d709c89a 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -104,9 +104,6 @@ static GTY(()) rtx zero_reg_rtx; /* AVR register names {"r0", "r1", ..., "r31"} */ static const char *const avr_regnames[] = REGISTER_NAMES; -/* This holds the last insn address. */ -static int last_insn_address = 0; - /* Preprocessor macros to define depending on MCU type. */ static const char *avr_extra_arch_macro; @@ -556,8 +553,6 @@ expand_prologue (void) rtx pushword = gen_rtx_MEM (HImode, gen_rtx_POST_DEC (HImode, stack_pointer_rtx)); rtx insn; - - last_insn_address = 0; /* Init cfun->machine. */ cfun->machine->is_naked = avr_naked_function_p (current_function_decl); @@ -1459,25 +1454,17 @@ byte_immediate_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED) && INTVAL (op) <= 0xff && INTVAL (op) >= 0); } -/* Output all insn addresses and their sizes into the assembly language - output file. This is helpful for debugging whether the length attributes - in the md file are correct. - Output insn cost for next insn. */ +/* Output insn cost for next insn. */ void final_prescan_insn (rtx insn, rtx *operand ATTRIBUTE_UNUSED, int num_operands ATTRIBUTE_UNUSED) { - int uid = INSN_UID (insn); - - if (TARGET_INSN_SIZE_DUMP || TARGET_ALL_DEBUG) + if (TARGET_ALL_DEBUG) { - fprintf (asm_out_file, "/*DEBUG: 0x%x\t\t%d\t%d */\n", - INSN_ADDRESSES (uid), - INSN_ADDRESSES (uid) - last_insn_address, + fprintf (asm_out_file, "/* DEBUG: cost = %d. */\n", rtx_cost (PATTERN (insn), INSN, !optimize_size)); } - last_insn_address = INSN_ADDRESSES (uid); } /* Return 0 if undefined, 1 if always true or always false. */ @@ -5890,12 +5877,12 @@ avr_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED, return 1; } -/* Output a branch that tests a single bit of a register (QI, HI or SImode) +/* Output a branch that tests a single bit of a register (QI, HI, SI or DImode) or memory location in the I/O space (QImode only). Operand 0: comparison operator (must be EQ or NE, compare bit to zero). Operand 1: register operand to test, or CONST_INT memory address. - Operand 2: bit number (for QImode operand) or mask (HImode, SImode). + Operand 2: bit number. Operand 3: label to jump to if the test is true. */ const char * @@ -5943,9 +5930,7 @@ avr_out_sbxx_branch (rtx insn, rtx operands[]) else /* HImode or SImode */ { static char buf[] = "sbrc %A1,0"; - int bit_nr = exact_log2 (INTVAL (operands[2]) - & GET_MODE_MASK (GET_MODE (operands[1]))); - + int bit_nr = INTVAL (operands[2]); buf[3] = (comp == EQ) ? 's' : 'c'; buf[6] = 'A' + (bit_nr >> 3); buf[9] = '0' + (bit_nr & 7); diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h index 0927e3928c1..782ad11627b 100644 --- a/gcc/config/avr/avr.h +++ b/gcc/config/avr/avr.h @@ -406,8 +406,6 @@ extern int avr_reg_order[]; #define HAVE_POST_INCREMENT 1 #define HAVE_PRE_DECREMENT 1 -#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) - #define MAX_REGS_PER_ADDRESS 1 #define REG_OK_FOR_BASE_NOSTRICT_P(X) \ diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md index 5a15200ffe3..51fc1f99b8b 100644 --- a/gcc/config/avr/avr.md +++ b/gcc/config/avr/avr.md @@ -118,6 +118,7 @@ ;; Define mode iterator (define_mode_iterator QISI [(QI "") (HI "") (SI "")]) +(define_mode_iterator QIDI [(QI "") (HI "") (SI "") (DI "")]) ;;======================================================================== ;; The following is used by nonlocal_goto and setjmp. @@ -235,7 +236,7 @@ (define_insn "*movqi" [(set (match_operand:QI 0 "nonimmediate_operand" "=r,d,Qm,r,q,r,*r") - (match_operand:QI 1 "general_operand" "r,i,rL,Qm,r,q,i"))] + (match_operand:QI 1 "general_operand" "rL,i,rL,Qm,r,q,i"))] "(register_operand (operands[0],QImode) || register_operand (operands[1], QImode) || const0_rtx == operands[1])" "* return output_movqi (insn, operands, NULL);" @@ -336,7 +337,7 @@ (define_insn "*movhi" [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,d,*r,q,r") - (match_operand:HI 1 "general_operand" "r,m,rL,i,i,r,q"))] + (match_operand:HI 1 "general_operand" "rL,m,rL,i,i,r,q"))] "(register_operand (operands[0],HImode) || register_operand (operands[1],HImode) || const0_rtx == operands[1])" "* return output_movhi (insn, operands, NULL);" @@ -2448,12 +2449,15 @@ ;; Test a single bit in a QI/HI/SImode register. -(define_insn "*sbrx_branch" +;; Combine will create zero extract patterns for single bit tests. +;; permit any mode in source pattern by using VOIDmode. + +(define_insn "*sbrx_branch" [(set (pc) (if_then_else (match_operator 0 "eqne_operator" - [(zero_extract:HI - (match_operand:QI 1 "register_operand" "r") + [(zero_extract:QIDI + (match_operand:VOID 1 "register_operand" "r") (const_int 1) (match_operand 2 "const_int_operand" "n")) (const_int 0)]) @@ -2470,39 +2474,27 @@ (const_int 4)))) (set_attr "cc" "clobber")]) -(define_insn "*sbrx_and_branchhi" - [(set (pc) - (if_then_else - (match_operator 0 "eqne_operator" - [(and:HI - (match_operand:HI 1 "register_operand" "r") - (match_operand:HI 2 "single_one_operand" "n")) - (const_int 0)]) - (label_ref (match_operand 3 "" "")) - (pc)))] - "" - "* return avr_out_sbxx_branch (insn, operands);" - [(set (attr "length") - (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046)) - (le (minus (pc) (match_dup 3)) (const_int 2046))) - (const_int 2) - (if_then_else (eq_attr "mcu_mega" "no") - (const_int 2) - (const_int 4)))) - (set_attr "cc" "clobber")]) +;; Same test based on Bitwise AND RTL. Keep this incase gcc changes patterns. +;; or for old peepholes. +;; Fixme - bitwise Mask will not work for DImode -(define_insn "*sbrx_and_branchsi" +(define_insn "*sbrx_and_branch" [(set (pc) (if_then_else (match_operator 0 "eqne_operator" - [(and:SI - (match_operand:SI 1 "register_operand" "r") - (match_operand:SI 2 "single_one_operand" "n")) + [(and:QISI + (match_operand:QISI 1 "register_operand" "r") + (match_operand:QISI 2 "single_one_operand" "n")) (const_int 0)]) (label_ref (match_operand 3 "" "")) (pc)))] "" - "* return avr_out_sbxx_branch (insn, operands);" +{ + HOST_WIDE_INT bitnumber; + bitnumber = exact_log2 (GET_MODE_MASK (mode) & INTVAL (operands[2])); + operands[2] = GEN_INT (bitnumber); + return avr_out_sbxx_branch (insn, operands); +} [(set (attr "length") (if_then_else (and (ge (minus (pc) (match_dup 3)) (const_int -2046)) (le (minus (pc) (match_dup 3)) (const_int 2046))) diff --git a/gcc/config/avr/avr.opt b/gcc/config/avr/avr.opt index f94d6a3c2ac..f8013e53a18 100644 --- a/gcc/config/avr/avr.opt +++ b/gcc/config/avr/avr.opt @@ -47,10 +47,6 @@ mshort-calls Target Report Mask(SHORT_CALLS) Use rjmp/rcall (limited range) on >8K devices -msize -Target Report Mask(INSN_SIZE_DUMP) -Output instruction sizes to the asm file - mtiny-stack Target Report Mask(TINY_STACK) Change only the low 8 bits of the stack pointer diff --git a/gcc/config/bfin/bfin.h b/gcc/config/bfin/bfin.h index 03a279036f3..365680ee9fa 100644 --- a/gcc/config/bfin/bfin.h +++ b/gcc/config/bfin/bfin.h @@ -911,9 +911,6 @@ typedef struct { /* Addressing Modes */ -/* Recognize any constant value that is a valid address. */ -#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) - /* Nonzero if the constant value X is a legitimate general operand. symbol_ref are not legitimate and will be put into constant pool. See force_const_mem(). diff --git a/gcc/config/cris/cris-protos.h b/gcc/config/cris/cris-protos.h index db6aa9fe9ce..721c90ff887 100644 --- a/gcc/config/cris/cris-protos.h +++ b/gcc/config/cris/cris-protos.h @@ -71,3 +71,5 @@ extern void cris_override_options (void); extern int cris_initial_elimination_offset (int, int); extern void cris_init_expanders (void); + +extern bool cris_function_value_regno_p (const unsigned int); diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c index bf00a57a3b6..225ad403dda 100644 --- a/gcc/config/cris/cris.c +++ b/gcc/config/cris/cris.c @@ -130,6 +130,9 @@ static bool cris_frame_pointer_required (void); static void cris_asm_trampoline_template (FILE *); static void cris_trampoline_init (rtx, tree, rtx); +static rtx cris_function_value(const_tree, const_tree, bool); +static rtx cris_libcall_value (enum machine_mode, const_rtx); + /* This is the parsed result of the "-max-stack-stackframe=" option. If it (still) is zero, then there was no such option given. */ int cris_max_stackframe = 0; @@ -197,6 +200,11 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION; #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT cris_trampoline_init +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE cris_function_value +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE cris_libcall_value + struct gcc_target targetm = TARGET_INITIALIZER; /* Helper for cris_load_multiple_op and cris_ret_movem_op. */ @@ -3777,13 +3785,42 @@ cris_promote_function_mode (const_tree type ATTRIBUTE_UNUSED, int for_return) { /* Defining PROMOTE_FUNCTION_RETURN in gcc-2.7.2 uncovered bug 981110 (even - when modifying FUNCTION_VALUE to return the promoted mode). Maybe - pointless as of now, but let's keep the old behavior. */ + when modifying TARGET_FUNCTION_VALUE to return the promoted mode). + Maybe pointless as of now, but let's keep the old behavior. */ if (for_return == 1) return mode; return CRIS_PROMOTED_MODE (mode, *punsignedp, type); } +/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the + time being. */ + +static rtx +cris_function_value(const_tree type, + const_tree func ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (TYPE_MODE (type), CRIS_FIRST_ARG_REG); +} + +/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the + time being. */ + +static rtx +cris_libcall_value (enum machine_mode mode, + const_rtx fun ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (mode, CRIS_FIRST_ARG_REG); +} + +/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the + time being. */ + +bool +cris_function_value_regno_p (const unsigned int regno) +{ + return (regno == CRIS_FIRST_ARG_REG); +} static int cris_arg_partial_bytes (CUMULATIVE_ARGS *ca, enum machine_mode mode, diff --git a/gcc/config/cris/cris.h b/gcc/config/cris/cris.h index 586f7ff2077..3c426b74ae5 100644 --- a/gcc/config/cris/cris.h +++ b/gcc/config/cris/cris.h @@ -630,12 +630,17 @@ enum reg_class ? GENERAL_REGS : (CLASS)) /* We can't move special registers to and from memory in smaller than - word_mode. */ -#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) \ - (((CLASS) != SPECIAL_REGS && (CLASS) != MOF_REGS) \ - || GET_MODE_SIZE (MODE) == 4 \ - || !MEM_P (X) \ - ? NO_REGS : GENERAL_REGS) + word_mode. We also can't move between special registers. Luckily, + -1, as returned by true_regnum for non-sub/registers, is valid as a + parameter to our REGNO_REG_CLASS, returning GENERAL_REGS, so we get + the effect that any X that isn't a special-register is treated as + a non-empty intersection with GENERAL_REGS. */ +#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) \ + ((((CLASS) == SPECIAL_REGS || (CLASS) == MOF_REGS) \ + && ((GET_MODE_SIZE (MODE) < 4 && MEM_P (X)) \ + || !reg_classes_intersect_p (REGNO_REG_CLASS (true_regnum (X)), \ + GENERAL_REGS))) \ + ? GENERAL_REGS : NO_REGS) /* FIXME: Fix regrename.c; it should check validity of replacements, not just with a silly pass-specific macro. We may miss some @@ -901,14 +906,8 @@ struct cum_args {int regs;}; /* Node: Scalar Return */ -/* Let's assume all functions return in r[CRIS_FIRST_ARG_REG] for the - time being. */ -#define FUNCTION_VALUE(VALTYPE, FUNC) \ - gen_rtx_REG (TYPE_MODE (VALTYPE), CRIS_FIRST_ARG_REG) +#define FUNCTION_VALUE_REGNO_P(N) cris_function_value_regno_p (N) -#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, CRIS_FIRST_ARG_REG) - -#define FUNCTION_VALUE_REGNO_P(N) ((N) == CRIS_FIRST_ARG_REG) /* Node: Aggregate Return */ @@ -951,8 +950,6 @@ struct cum_args {int regs;}; #define HAVE_POST_INCREMENT 1 -#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) - /* Must be a compile-time constant, so we go with the highest value among all CRIS variants. */ #define MAX_REGS_PER_ADDRESS 2 diff --git a/gcc/config/cris/cris.md b/gcc/config/cris/cris.md index 79eb8da3b0d..bd14a16337e 100644 --- a/gcc/config/cris/cris.md +++ b/gcc/config/cris/cris.md @@ -4936,7 +4936,7 @@ ;; It should be: ;; movu.b some_byte,reg_32 ;; and.b const,reg_32 -;; but is turns into: +;; but it turns into: ;; move.b some_byte,reg_32 ;; and.d const,reg_32 ;; Fix it here. @@ -4953,7 +4953,9 @@ "REGNO (operands[2]) == REGNO (operands[0]) && INTVAL (operands[3]) <= 65535 && INTVAL (operands[3]) >= 0 && !CRIS_CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'I') - && !side_effects_p (operands[1])" + && !side_effects_p (operands[1]) + && (!REG_P (operands[1]) + || REGNO (operands[1]) <= CRIS_LAST_GENERAL_REGISTER)" ;; FIXME: CC0 valid except for M (i.e. CC_NOT_NEGATIVE). [(set (match_dup 0) (match_dup 4)) (set (match_dup 5) (match_dup 6))] diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c index a8933e66348..b5c4fb8e0d9 100644 --- a/gcc/config/darwin.c +++ b/gcc/config/darwin.c @@ -1697,6 +1697,17 @@ darwin_override_options (void) if (dwarf_strict < 0) dwarf_strict = 1; + /* Disable -freorder-blocks-and-partition for darwin_emit_unwind_label. */ + if (flag_reorder_blocks_and_partition + && (targetm.asm_out.unwind_label == darwin_emit_unwind_label)) + { + inform (input_location, + "-freorder-blocks-and-partition does not work with exceptions " + "on this architecture"); + flag_reorder_blocks_and_partition = 0; + flag_reorder_blocks = 1; + } + if (flag_mkernel || flag_apple_kext) { /* -mkernel implies -fapple-kext for C++ */ diff --git a/gcc/config/darwin10.h b/gcc/config/darwin10.h index 65ba2632a8f..b1edf36ce3d 100644 --- a/gcc/config/darwin10.h +++ b/gcc/config/darwin10.h @@ -23,3 +23,8 @@ unwinder in libSystem is fixed to digest new epilog unwinding notes. */ #undef LIB_SPEC #define LIB_SPEC "%{!static:-no_compact_unwind -lSystem}" + +/* Unwind labels are no longer required in darwin10. */ + +#undef TARGET_ASM_EMIT_UNWIND_LABEL +#define TARGET_ASM_EMIT_UNWIND_LABEL default_emit_unwind_label diff --git a/gcc/config/fr30/fr30.h b/gcc/config/fr30/fr30.h index 20e157173d8..5e6237895b5 100644 --- a/gcc/config/fr30/fr30.h +++ b/gcc/config/fr30/fr30.h @@ -741,16 +741,6 @@ enum reg_class /*}}}*/ /*{{{ Addressing Modes. */ -/* A C expression that is 1 if the RTX X is a constant which is a valid - address. On most machines, this can be defined as `CONSTANT_P (X)', but a - few machines are more restrictive in which constant addresses are supported. - - `CONSTANT_P' accepts integer-values expressions whose values are not - explicitly known, such as `symbol_ref', `label_ref', and `high' expressions - and `const' arithmetic expressions, in addition to `const_int' and - `const_double' expressions. */ -#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) - /* A number, the maximum number of registers that can appear in a valid memory address. Note that it is up to you to specify a value equal to the maximum number that `GO_IF_LEGITIMATE_ADDRESS' would ever accept. */ diff --git a/gcc/config/frv/frv-protos.h b/gcc/config/frv/frv-protos.h index 2bfdc65f654..3c9950d740b 100644 --- a/gcc/config/frv/frv-protos.h +++ b/gcc/config/frv/frv-protos.h @@ -62,6 +62,7 @@ extern rtx frv_function_arg (CUMULATIVE_ARGS *, extern void frv_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, tree, int); +extern bool frv_function_value_regno_p (const unsigned int); #endif /* TREE_CODE */ extern int frv_expand_block_move (rtx *); diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c index d8901e9a68e..a757472f37b 100644 --- a/gcc/config/frv/frv.c +++ b/gcc/config/frv/frv.c @@ -273,6 +273,10 @@ static void frv_print_operand_memory_reference_reg static void frv_print_operand_memory_reference (FILE *, rtx, int); static int frv_print_operand_jump_hint (rtx); static const char *comparison_string (enum rtx_code, rtx); +static rtx frv_function_value (const_tree, const_tree, + bool); +static rtx frv_libcall_value (enum machine_mode, + const_rtx); static FRV_INLINE int frv_regno_ok_for_base_p (int, int); static rtx single_set_pattern (rtx); static int frv_function_contains_far_jump (void); @@ -483,6 +487,11 @@ static void frv_trampoline_init (rtx, tree, rtx); #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT frv_trampoline_init +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE frv_function_value +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE frv_libcall_value + struct gcc_target targetm = TARGET_INITIALIZER; #define FRV_SYMBOL_REF_TLS_P(RTX) \ @@ -3291,6 +3300,35 @@ frv_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode, } +/* Implements TARGET_FUNCTION_VALUE. */ + +static rtx +frv_function_value (const_tree valtype, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (TYPE_MODE (valtype), RETURN_VALUE_REGNUM); +} + + +/* Implements TARGET_LIBCALL_VALUE. */ + +static rtx +frv_libcall_value (enum machine_mode mode, + const_rtx fun ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (mode, RETURN_VALUE_REGNUM); +} + + +/* Implements FUNCTION_VALUE_REGNO_P. */ + +bool +frv_function_value_regno_p (const unsigned int regno) +{ + return (regno == RETURN_VALUE_REGNUM); +} + /* Return true if a register is ok to use as a base or index register. */ static FRV_INLINE int diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h index 53966de50b7..d5a7a4a6670 100644 --- a/gcc/config/frv/frv.h +++ b/gcc/config/frv/frv.h @@ -1746,48 +1746,7 @@ typedef struct frv_stack { function call. */ #define RETURN_VALUE_REGNUM (GPR_FIRST + 8) -/* A C expression to create an RTX representing the place where a function - returns a value of data type VALTYPE. VALTYPE is a tree node representing a - data type. Write `TYPE_MODE (VALTYPE)' to get the machine mode used to - represent that type. On many machines, only the mode is relevant. - (Actually, on most machines, scalar values are returned in the same place - regardless of mode). - - If the precise function being called is known, FUNC is a tree node - (`FUNCTION_DECL') for it; otherwise, FUNC is a null pointer. This makes it - possible to use a different value-returning convention for specific - functions when all their calls are known. - - `FUNCTION_VALUE' is not used for return vales with aggregate data types, - because these are returned in another way. See - `TARGET_STRUCT_VALUE_RTX' and related macros, below. */ -#define FUNCTION_VALUE(VALTYPE, FUNC) \ - gen_rtx_REG (TYPE_MODE (VALTYPE), RETURN_VALUE_REGNUM) - -/* A C expression to create an RTX representing the place where a library - function returns a value of mode MODE. - - Note that "library function" in this context means a compiler support - routine, used to perform arithmetic, whose name is known specially by the - compiler and was not mentioned in the C code being compiled. - - The definition of `LIBRARY_VALUE' need not be concerned aggregate data - types, because none of the library functions returns such types. */ -#define LIBCALL_VALUE(MODE) gen_rtx_REG (MODE, RETURN_VALUE_REGNUM) - -/* A C expression that is nonzero if REGNO is the number of a hard register in - which the values of called function may come back. - - A register whose use for returning values is limited to serving as the - second of a pair (for a value of type `double', say) need not be recognized - by this macro. So for most machines, this definition suffices: - - #define FUNCTION_VALUE_REGNO_P(N) ((N) == RETURN) - - If the machine has register windows, so that the caller and the called - function use different registers for the return value, this macro should - recognize only the caller's register numbers. */ -#define FUNCTION_VALUE_REGNO_P(REGNO) ((REGNO) == RETURN_VALUE_REGNUM) +#define FUNCTION_VALUE_REGNO_P(REGNO) frv_function_value_regno_p (REGNO) /* How Large Values are Returned. */ @@ -1968,16 +1927,6 @@ __asm__("\n" \ /* Addressing Modes. */ -/* A C expression that is 1 if the RTX X is a constant which is a valid - address. On most machines, this can be defined as `CONSTANT_P (X)', but a - few machines are more restrictive in which constant addresses are supported. - - `CONSTANT_P' accepts integer-values expressions whose values are not - explicitly known, such as `symbol_ref', `label_ref', and `high' expressions - and `const' arithmetic expressions, in addition to `const_int' and - `const_double' expressions. */ -#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) - /* A number, the maximum number of registers that can appear in a valid memory address. Note that it is up to you to specify a value equal to the maximum number that `TARGET_LEGITIMATE_ADDRESS_P' would ever accept. */ diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c index 404595405f3..7bb1e7a6c5c 100644 --- a/gcc/config/h8300/h8300.c +++ b/gcc/config/h8300/h8300.c @@ -507,6 +507,32 @@ byte_reg (rtx x, int b) && call_used_regs[regno] \ && !current_function_is_leaf))) +/* We use this to wrap all emitted insns in the prologue. */ +static rtx +F (rtx x) +{ + RTX_FRAME_RELATED_P (x) = 1; + return x; +} + +/* Mark all the subexpressions of the PARALLEL rtx PAR as + frame-related. Return PAR. + + dwarf2out.c:dwarf2out_frame_debug_expr ignores sub-expressions of a + PARALLEL rtx other than the first if they do not have the + FRAME_RELATED flag set on them. */ +static rtx +Fpa (rtx par) +{ + int len = XVECLEN (par, 0); + int i; + + for (i = 0; i < len; i++) + F (XVECEXP (par, 0, i)); + + return par; +} + /* Output assembly language to FILE for the operation OP with operand size SIZE to adjust the stack pointer. */ @@ -526,22 +552,27 @@ h8300_emit_stack_adjustment (int sign, HOST_WIDE_INT size) && !(cfun->static_chain_decl != NULL && sign < 0)) { rtx r3 = gen_rtx_REG (Pmode, 3); - emit_insn (gen_movhi (r3, GEN_INT (sign * size))); - emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, r3)); + F (emit_insn (gen_movhi (r3, GEN_INT (sign * size)))); + F (emit_insn (gen_addhi3 (stack_pointer_rtx, + stack_pointer_rtx, r3))); } else { /* The stack adjustment made here is further optimized by the splitter. In case of H8/300, the splitter always splits the - addition emitted here to make the adjustment - interrupt-safe. */ + addition emitted here to make the adjustment interrupt-safe. + FIXME: We don't always tag those, because we don't know what + the splitter will do. */ if (Pmode == HImode) - emit_insn (gen_addhi3 (stack_pointer_rtx, - stack_pointer_rtx, GEN_INT (sign * size))); + { + rtx x = emit_insn (gen_addhi3 (stack_pointer_rtx, + stack_pointer_rtx, GEN_INT (sign * size))); + if (size < 4) + F (x); + } else - emit_insn (gen_addsi3 (stack_pointer_rtx, - stack_pointer_rtx, GEN_INT (sign * size))); + F (emit_insn (gen_addsi3 (stack_pointer_rtx, + stack_pointer_rtx, GEN_INT (sign * size)))); } } @@ -591,7 +622,7 @@ push (int rn) x = gen_push_h8300hs_advanced (reg); else x = gen_push_h8300hs_normal (reg); - x = emit_insn (x); + x = F (emit_insn (x)); REG_NOTES (x) = gen_rtx_EXPR_LIST (REG_INC, stack_pointer_rtx, 0); } @@ -634,7 +665,7 @@ h8300_push_pop (int regno, int nregs, int pop_p, int return_p) { int i, j; rtvec vec; - rtx sp, offset; + rtx sp, offset, x; /* See whether we can use a simple push or pop. */ if (!return_p && nregs == 1) @@ -685,7 +716,10 @@ h8300_push_pop (int regno, int nregs, int pop_p, int return_p) RTVEC_ELT (vec, i + j) = gen_rtx_SET (VOIDmode, sp, gen_rtx_PLUS (Pmode, sp, offset)); - emit_insn (gen_rtx_PARALLEL (VOIDmode, vec)); + x = gen_rtx_PARALLEL (VOIDmode, vec); + if (!pop_p) + x = Fpa (x); + emit_insn (x); } /* Return true if X has the value sp + OFFSET. */ @@ -820,7 +854,7 @@ h8300_expand_prologue (void) { /* Push fp. */ push (HARD_FRAME_POINTER_REGNUM); - emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx); + F (emit_move_insn (hard_frame_pointer_rtx, stack_pointer_rtx)); } /* Push the rest of the registers in ascending order. */ diff --git a/gcc/config/h8300/h8300.h b/gcc/config/h8300/h8300.h index e0f0ea62f4e..9757afc2de3 100644 --- a/gcc/config/h8300/h8300.h +++ b/gcc/config/h8300/h8300.h @@ -147,6 +147,17 @@ extern const char * const *h8_reg_names; /* Show we can debug even without a frame pointer. */ /* #define CAN_DEBUG_WITHOUT_FP */ +/* We want dwarf2 info available to gdb... */ +#define DWARF2_DEBUGGING_INFO 1 +/* ... but we don't actually support full dwarf2 EH. */ +#define MUST_USE_SJLJ_EXCEPTIONS 1 + +/* The return address is pushed on the stack. */ +#define INCOMING_RETURN_ADDR_RTX gen_rtx_MEM (Pmode, gen_rtx_REG (Pmode, STACK_POINTER_REGNUM)) +#define INCOMING_FRAME_SP_OFFSET (POINTER_SIZE / 8) + +#define DWARF_CIE_DATA_ALIGNMENT 2 + /* Define this if addresses of constant functions shouldn't be put through pseudo regs where they can be cse'd. Desirable on machines where ordinary constants are expensive diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h index 49acfa780e4..21f0e3184ef 100644 --- a/gcc/config/i386/cpuid.h +++ b/gcc/config/i386/cpuid.h @@ -46,9 +46,11 @@ /* Extended Features */ /* %ecx */ +#define bit_FMA4 (1 << 16) #define bit_LAHF_LM (1 << 0) +#define bit_LWP (1 << 15) #define bit_SSE4a (1 << 6) -#define bit_FMA4 (1 << 16) +#define bit_XOP (1 << 11) /* %edx */ #define bit_LM (1 << 29) diff --git a/gcc/config/i386/cygming.h b/gcc/config/i386/cygming.h index 43003cc5cad..cdab21c91a2 100644 --- a/gcc/config/i386/cygming.h +++ b/gcc/config/i386/cygming.h @@ -49,8 +49,9 @@ along with GCC; see the file COPYING3. If not see target, always use the svr4_dbx_register_map for DWARF .eh_frame even if we don't use DWARF .debug_frame. */ #undef DWARF_FRAME_REGNUM -#define DWARF_FRAME_REGNUM(n) TARGET_64BIT \ - ? dbx64_register_map[(n)] : svr4_dbx_register_map[(n)] +#define DWARF_FRAME_REGNUM(n) \ + (TARGET_64BIT ? dbx64_register_map[(n)] \ + : svr4_dbx_register_map[(n)]) #ifdef HAVE_GAS_PE_SECREL32_RELOC /* Use section relative relocations for debugging offsets. Unlike diff --git a/gcc/config/i386/fma4intrin.h b/gcc/config/i386/fma4intrin.h index 42782ade0ed..2bd411a0f05 100644 --- a/gcc/config/i386/fma4intrin.h +++ b/gcc/config/i386/fma4intrin.h @@ -35,15 +35,6 @@ /* We need definitions from the SSE4A, SSE3, SSE2 and SSE header files. */ #include -/* Internal data types for implementing the intrinsics. */ -typedef float __v8sf __attribute__ ((__vector_size__ (32))); -typedef double __v4df __attribute__ ((__vector_size__ (32))); - -typedef float __m256 __attribute__ ((__vector_size__ (32), - __may_alias__)); -typedef double __m256d __attribute__ ((__vector_size__ (32), - __may_alias__)); - /* 128b Floating point multiply/add type instructions. */ extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) _mm_macc_ps (__m128 __A, __m128 __B, __m128 __C) diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c index 12a3f1759a8..5a5311fba0f 100644 --- a/gcc/config/i386/i386-c.c +++ b/gcc/config/i386/i386-c.c @@ -232,6 +232,10 @@ ix86_target_macros_internal (int isa_flag, def_or_undef (parse_in, "__SSE4A__"); if (isa_flag & OPTION_MASK_ISA_FMA4) def_or_undef (parse_in, "__FMA4__"); + if (isa_flag & OPTION_MASK_ISA_XOP) + def_or_undef (parse_in, "__XOP__"); + if (isa_flag & OPTION_MASK_ISA_LWP) + def_or_undef (parse_in, "__LWP__"); if ((fpmath & FPMATH_SSE) && (isa_flag & OPTION_MASK_ISA_SSE)) def_or_undef (parse_in, "__SSE_MATH__"); if ((fpmath & FPMATH_SSE) && (isa_flag & OPTION_MASK_ISA_SSE2)) diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 9df01ba23dc..2031dfb6e98 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -1553,6 +1553,11 @@ static unsigned int initial_ix86_arch_features[X86_ARCH_LAST] = { /* X86_ARCH_BSWAP: Byteswap was added for 80486. */ ~m_386, + + /* X86_ARCH_CALL_ESP: P6 processors will jump to the address after + the decrement (so they will execute return address as code). See + Pentium Pro errata 70, Pentium 2 errata A33, Pentium 3 errata E17. */ + ~(m_386 | m_486 | m_PENT | m_PPRO), }; static const unsigned int x86_accumulate_outgoing_args @@ -1905,6 +1910,7 @@ static bool ix86_valid_target_attribute_p (tree, tree, tree, int); static bool ix86_valid_target_attribute_inner_p (tree, char *[]); static bool ix86_can_inline_p (tree, tree); static void ix86_set_current_function (tree); +static unsigned int ix86_minimum_incoming_stack_boundary (bool); static enum calling_abi ix86_function_abi (const_tree); @@ -1958,6 +1964,10 @@ static int ix86_isa_flags_explicit; #define OPTION_MASK_ISA_FMA4_SET \ (OPTION_MASK_ISA_FMA4 | OPTION_MASK_ISA_SSE4A_SET \ | OPTION_MASK_ISA_AVX_SET) +#define OPTION_MASK_ISA_XOP_SET \ + (OPTION_MASK_ISA_XOP | OPTION_MASK_ISA_FMA4_SET) +#define OPTION_MASK_ISA_LWP_SET \ + OPTION_MASK_ISA_LWP /* AES and PCLMUL need SSE2 because they use xmm registers */ #define OPTION_MASK_ISA_AES_SET \ @@ -2009,7 +2019,10 @@ static int ix86_isa_flags_explicit; #define OPTION_MASK_ISA_SSE4A_UNSET \ (OPTION_MASK_ISA_SSE4A | OPTION_MASK_ISA_FMA4_UNSET) -#define OPTION_MASK_ISA_FMA4_UNSET OPTION_MASK_ISA_FMA4 +#define OPTION_MASK_ISA_FMA4_UNSET \ + (OPTION_MASK_ISA_FMA4 | OPTION_MASK_ISA_XOP_UNSET) +#define OPTION_MASK_ISA_XOP_UNSET OPTION_MASK_ISA_XOP +#define OPTION_MASK_ISA_LWP_UNSET OPTION_MASK_ISA_LWP #define OPTION_MASK_ISA_AES_UNSET OPTION_MASK_ISA_AES #define OPTION_MASK_ISA_PCLMUL_UNSET OPTION_MASK_ISA_PCLMUL @@ -2257,6 +2270,32 @@ ix86_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value) } return true; + case OPT_mxop: + if (value) + { + ix86_isa_flags |= OPTION_MASK_ISA_XOP_SET; + ix86_isa_flags_explicit |= OPTION_MASK_ISA_XOP_SET; + } + else + { + ix86_isa_flags &= ~OPTION_MASK_ISA_XOP_UNSET; + ix86_isa_flags_explicit |= OPTION_MASK_ISA_XOP_UNSET; + } + return true; + + case OPT_mlwp: + if (value) + { + ix86_isa_flags |= OPTION_MASK_ISA_LWP_SET; + ix86_isa_flags_explicit |= OPTION_MASK_ISA_LWP_SET; + } + else + { + ix86_isa_flags &= ~OPTION_MASK_ISA_LWP_UNSET; + ix86_isa_flags_explicit |= OPTION_MASK_ISA_LWP_UNSET; + } + return true; + case OPT_mabm: if (value) { @@ -2385,6 +2424,8 @@ ix86_target_string (int isa, int flags, const char *arch, const char *tune, { { "-m64", OPTION_MASK_ISA_64BIT }, { "-mfma4", OPTION_MASK_ISA_FMA4 }, + { "-mxop", OPTION_MASK_ISA_XOP }, + { "-mlwp", OPTION_MASK_ISA_LWP }, { "-msse4a", OPTION_MASK_ISA_SSE4A }, { "-msse4.2", OPTION_MASK_ISA_SSE4_2 }, { "-msse4.1", OPTION_MASK_ISA_SSE4_1 }, @@ -2615,7 +2656,9 @@ override_options (bool main_args_p) PTA_AVX = 1 << 18, PTA_FMA = 1 << 19, PTA_MOVBE = 1 << 20, - PTA_FMA4 = 1 << 21 + PTA_FMA4 = 1 << 21, + PTA_XOP = 1 << 22, + PTA_LWP = 1 << 23 }; static struct pta @@ -2961,6 +3004,12 @@ override_options (bool main_args_p) if (processor_alias_table[i].flags & PTA_FMA4 && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_FMA4)) ix86_isa_flags |= OPTION_MASK_ISA_FMA4; + if (processor_alias_table[i].flags & PTA_XOP + && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_XOP)) + ix86_isa_flags |= OPTION_MASK_ISA_XOP; + if (processor_alias_table[i].flags & PTA_LWP + && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_LWP)) + ix86_isa_flags |= OPTION_MASK_ISA_LWP; if (processor_alias_table[i].flags & PTA_ABM && !(ix86_isa_flags_explicit & OPTION_MASK_ISA_ABM)) ix86_isa_flags |= OPTION_MASK_ISA_ABM; @@ -3239,12 +3288,10 @@ override_options (bool main_args_p) if (ix86_force_align_arg_pointer == -1) ix86_force_align_arg_pointer = STACK_REALIGN_DEFAULT; + ix86_default_incoming_stack_boundary = PREFERRED_STACK_BOUNDARY; + /* Validate -mincoming-stack-boundary= value or default it to MIN_STACK_BOUNDARY/PREFERRED_STACK_BOUNDARY. */ - if (ix86_force_align_arg_pointer) - ix86_default_incoming_stack_boundary = MIN_STACK_BOUNDARY; - else - ix86_default_incoming_stack_boundary = PREFERRED_STACK_BOUNDARY; ix86_incoming_stack_boundary = ix86_default_incoming_stack_boundary; if (ix86_incoming_stack_boundary_string) { @@ -3394,7 +3441,7 @@ override_options (bool main_args_p) ix86_gen_pop1 = gen_popdi1; ix86_gen_add3 = gen_adddi3; ix86_gen_sub3 = gen_subdi3; - ix86_gen_sub3_carry = gen_subdi3_carry_rex64; + ix86_gen_sub3_carry = gen_subdi3_carry; ix86_gen_one_cmpl2 = gen_one_cmpldi2; ix86_gen_monitor = gen_sse3_monitor64; ix86_gen_andsp = gen_anddi3; @@ -3645,6 +3692,8 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[]) IX86_ATTR_ISA ("sse4a", OPT_msse4a), IX86_ATTR_ISA ("ssse3", OPT_mssse3), IX86_ATTR_ISA ("fma4", OPT_mfma4), + IX86_ATTR_ISA ("xop", OPT_mxop), + IX86_ATTR_ISA ("lwp", OPT_mlwp), /* string options */ IX86_ATTR_STR ("arch=", IX86_FUNCTION_SPECIFIC_ARCH), @@ -4277,7 +4326,8 @@ ix86_function_ok_for_sibcall (tree decl, tree exp) /* If we need to align the outgoing stack, then sibcalling would unalign the stack, which may break the called function. */ - if (ix86_incoming_stack_boundary < PREFERRED_STACK_BOUNDARY) + if (ix86_minimum_incoming_stack_boundary (true) + < PREFERRED_STACK_BOUNDARY) return false; if (decl) @@ -4774,6 +4824,25 @@ ix86_function_type_abi (const_tree fntype) return ix86_abi; } +static bool +ix86_function_ms_hook_prologue (const_tree fntype) +{ + if (!TARGET_64BIT) + { + if (lookup_attribute ("ms_hook_prologue", DECL_ATTRIBUTES (fntype))) + { + if (decl_function_context (fntype) != NULL_TREE) + { + error_at (DECL_SOURCE_LOCATION (fntype), + "ms_hook_prologue is not compatible with nested function"); + } + + return true; + } + } + return false; +} + static enum calling_abi ix86_function_abi (const_tree fndecl) { @@ -8177,37 +8246,58 @@ find_drap_reg (void) } } -/* Update incoming stack boundary and estimated stack alignment. */ +/* Return minimum incoming stack alignment. */ -static void -ix86_update_stack_boundary (void) +static unsigned int +ix86_minimum_incoming_stack_boundary (bool sibcall) { + unsigned int incoming_stack_boundary; + /* Prefer the one specified at command line. */ - ix86_incoming_stack_boundary - = (ix86_user_incoming_stack_boundary - ? ix86_user_incoming_stack_boundary - : ix86_default_incoming_stack_boundary); + if (ix86_user_incoming_stack_boundary) + incoming_stack_boundary = ix86_user_incoming_stack_boundary; + /* In 32bit, use MIN_STACK_BOUNDARY for incoming stack boundary + if -mstackrealign is used, it isn't used for sibcall check and + estimated stack alignment is 128bit. */ + else if (!sibcall + && !TARGET_64BIT + && ix86_force_align_arg_pointer + && crtl->stack_alignment_estimated == 128) + incoming_stack_boundary = MIN_STACK_BOUNDARY; + else + incoming_stack_boundary = ix86_default_incoming_stack_boundary; /* Incoming stack alignment can be changed on individual functions via force_align_arg_pointer attribute. We use the smallest incoming stack boundary. */ - if (ix86_incoming_stack_boundary > MIN_STACK_BOUNDARY + if (incoming_stack_boundary > MIN_STACK_BOUNDARY && lookup_attribute (ix86_force_align_arg_pointer_string, TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl)))) - ix86_incoming_stack_boundary = MIN_STACK_BOUNDARY; + incoming_stack_boundary = MIN_STACK_BOUNDARY; /* The incoming stack frame has to be aligned at least at parm_stack_boundary. */ - if (ix86_incoming_stack_boundary < crtl->parm_stack_boundary) - ix86_incoming_stack_boundary = crtl->parm_stack_boundary; + if (incoming_stack_boundary < crtl->parm_stack_boundary) + incoming_stack_boundary = crtl->parm_stack_boundary; /* Stack at entrance of main is aligned by runtime. We use the smallest incoming stack boundary. */ - if (ix86_incoming_stack_boundary > MAIN_STACK_BOUNDARY + if (incoming_stack_boundary > MAIN_STACK_BOUNDARY && DECL_NAME (current_function_decl) && MAIN_NAME_P (DECL_NAME (current_function_decl)) && DECL_FILE_SCOPE_P (current_function_decl)) - ix86_incoming_stack_boundary = MAIN_STACK_BOUNDARY; + incoming_stack_boundary = MAIN_STACK_BOUNDARY; + + return incoming_stack_boundary; +} + +/* Update incoming stack boundary and estimated stack alignment. */ + +static void +ix86_update_stack_boundary (void) +{ + ix86_incoming_stack_boundary + = ix86_minimum_incoming_stack_boundary (false); /* x86_64 vararg needs 16byte stack alignment for register save area. */ @@ -8295,6 +8385,7 @@ ix86_expand_prologue (void) bool pic_reg_used; struct ix86_frame frame; HOST_WIDE_INT allocate; + int gen_frame_pointer = frame_pointer_needed; ix86_finalize_stack_realign_flags (); @@ -8307,6 +8398,46 @@ ix86_expand_prologue (void) ix86_compute_frame_layout (&frame); + if (ix86_function_ms_hook_prologue (current_function_decl)) + { + rtx push, mov; + + /* Make sure the function starts with + 8b ff movl.s %edi,%edi + 55 push %ebp + 8b ec movl.s %esp,%ebp + + This matches the hookable function prologue in Win32 API + functions in Microsoft Windows XP Service Pack 2 and newer. + Wine uses this to enable Windows apps to hook the Win32 API + functions provided by Wine. */ + insn = emit_insn (gen_vswapmov (gen_rtx_REG (SImode, DI_REG), + gen_rtx_REG (SImode, DI_REG))); + push = emit_insn (gen_push (hard_frame_pointer_rtx)); + mov = emit_insn (gen_vswapmov (hard_frame_pointer_rtx, + stack_pointer_rtx)); + + if (frame_pointer_needed && !(crtl->drap_reg + && crtl->stack_realign_needed)) + { + /* The push %ebp and movl.s %esp, %ebp already set up + the frame pointer. No need to do this again. */ + gen_frame_pointer = 0; + RTX_FRAME_RELATED_P (push) = 1; + RTX_FRAME_RELATED_P (mov) = 1; + if (ix86_cfa_state->reg == stack_pointer_rtx) + ix86_cfa_state->reg = hard_frame_pointer_rtx; + } + else + /* If the frame pointer is not needed, pop %ebp again. This + could be optimized for cases where ebp needs to be backed up + for some other reason. If stack realignment is needed, pop + the base pointer again, align the stack, and later regenerate + the frame pointer setup. The frame pointer generated by the + hook prologue is not aligned, so it can't be used. */ + insn = emit_insn ((*ix86_gen_pop1) (hard_frame_pointer_rtx)); + } + /* The first insn of a function that accepts its static chain on the stack is to push the register that would be filled in by a direct call. This insn will be skipped by the trampoline. */ @@ -8378,7 +8509,7 @@ ix86_expand_prologue (void) /* Note: AT&T enter does NOT have reversed args. Enter is probably slower on all targets. Also sdb doesn't like it. */ - if (frame_pointer_needed) + if (gen_frame_pointer) { insn = emit_insn (gen_push (hard_frame_pointer_rtx)); RTX_FRAME_RELATED_P (insn) = 1; @@ -8962,7 +9093,8 @@ ix86_expand_epilogue (int style) 0, red_offset, style == 2); pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx, - GEN_INT (frame.nsseregs * 16 + frame.padding0), + GEN_INT (frame.nsseregs * 16 + + frame.padding0), style, false); } else if (frame.to_allocate || frame.padding0 || frame.nsseregs) @@ -10733,7 +10865,7 @@ i386_output_dwarf_dtprel (FILE *file, int size, rtx x) static bool ix86_pic_register_p (rtx x) { - if (GET_CODE (x) == VALUE) + if (GET_CODE (x) == VALUE && CSELIB_VAL_PTR (x)) return (pic_offset_table_rtx && rtx_equal_for_cselib_p (x, pic_offset_table_rtx)); else @@ -11203,6 +11335,7 @@ get_some_local_dynamic_name (void) X -- don't print any sort of PIC '@' suffix for a symbol. & -- print some in-use local-dynamic symbol name. H -- print a memory address offset by 8; used for sse high-parts + Y -- print condition for XOP pcom* instruction. + -- print a branch hint as 'cs' or 'ds' prefix ; -- print a semicolon (after prefixes due to bug in older gas). */ @@ -11620,6 +11753,61 @@ print_operand (FILE *file, rtx x, int code) return; } + case 'Y': + switch (GET_CODE (x)) + { + case NE: + fputs ("neq", file); + break; + case EQ: + fputs ("eq", file); + break; + case GE: + case GEU: + fputs (INTEGRAL_MODE_P (GET_MODE (x)) ? "ge" : "unlt", file); + break; + case GT: + case GTU: + fputs (INTEGRAL_MODE_P (GET_MODE (x)) ? "gt" : "unle", file); + break; + case LE: + case LEU: + fputs ("le", file); + break; + case LT: + case LTU: + fputs ("lt", file); + break; + case UNORDERED: + fputs ("unord", file); + break; + case ORDERED: + fputs ("ord", file); + break; + case UNEQ: + fputs ("ueq", file); + break; + case UNGE: + fputs ("nlt", file); + break; + case UNGT: + fputs ("nle", file); + break; + case UNLE: + fputs ("ule", file); + break; + case UNLT: + fputs ("ult", file); + break; + case LTGT: + fputs ("une", file); + break; + default: + output_operand_lossage ("operand is not a condition code, invalid operand code 'D'"); + return; + } + return; + case ';': #if TARGET_MACHO fputs (" ; ", file); @@ -12637,7 +12825,7 @@ ix86_expand_clear (rtx dest) tmp = gen_rtx_SET (VOIDmode, dest, const0_rtx); /* This predicate should match that for movsi_xor and movdi_xor_rex64. */ - if (reload_completed && (!TARGET_USE_MOV0 || optimize_insn_for_speed_p ())) + if (!TARGET_USE_MOV0 || optimize_insn_for_speed_p ()) { rtx clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG)); tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob)); @@ -15247,9 +15435,10 @@ ix86_expand_int_movcc (rtx operands[]) tmp = gen_reg_rtx (mode); if (mode == DImode) - emit_insn (gen_x86_movdicc_0_m1_rex64 (tmp, compare_op)); + emit_insn (gen_x86_movdicc_0_m1 (tmp, compare_op)); else - emit_insn (gen_x86_movsicc_0_m1 (gen_lowpart (SImode, tmp), compare_op)); + emit_insn (gen_x86_movsicc_0_m1 (gen_lowpart (SImode, tmp), + compare_op)); } else { @@ -15828,6 +16017,14 @@ ix86_expand_sse_movcc (rtx dest, rtx cmp, rtx op_true, rtx op_false) x = gen_rtx_AND (mode, x, op_false); emit_insn (gen_rtx_SET (VOIDmode, dest, x)); } + else if (TARGET_XOP) + { + rtx pcmov = gen_rtx_SET (mode, dest, + gen_rtx_IF_THEN_ELSE (mode, cmp, + op_true, + op_false)); + emit_insn (pcmov); + } else { op_true = force_reg (mode, op_true); @@ -15950,6 +16147,9 @@ ix86_expand_int_vcond (rtx operands[]) cop0 = operands[4]; cop1 = operands[5]; + /* XOP supports all of the comparisons on all vector int types. */ + if (!TARGET_XOP) + { /* Canonicalize the comparison to EQ, GT, GTU. */ switch (code) { @@ -16060,6 +16260,7 @@ ix86_expand_int_vcond (rtx operands[]) cop0 = x; cop1 = CONST0_RTX (mode); } + } x = ix86_expand_sse_cmp (operands[0], code, cop0, cop1, operands[1+negate], operands[2-negate]); @@ -16171,6 +16372,7 @@ int ix86_expand_int_addcc (rtx operands[]) { enum rtx_code code = GET_CODE (operands[1]); + rtx (*insn)(rtx, rtx, rtx, rtx); rtx compare_op; rtx val = const0_rtx; bool fpcmp = false; @@ -16211,16 +16413,16 @@ ix86_expand_int_addcc (rtx operands[]) switch (GET_MODE (operands[0])) { case QImode: - emit_insn (gen_subqi3_carry (operands[0], operands[2], val, compare_op)); + insn = gen_subqi3_carry; break; case HImode: - emit_insn (gen_subhi3_carry (operands[0], operands[2], val, compare_op)); + insn = gen_subhi3_carry; break; case SImode: - emit_insn (gen_subsi3_carry (operands[0], operands[2], val, compare_op)); + insn = gen_subsi3_carry; break; case DImode: - emit_insn (gen_subdi3_carry_rex64 (operands[0], operands[2], val, compare_op)); + insn = gen_subdi3_carry; break; default: gcc_unreachable (); @@ -16231,21 +16433,23 @@ ix86_expand_int_addcc (rtx operands[]) switch (GET_MODE (operands[0])) { case QImode: - emit_insn (gen_addqi3_carry (operands[0], operands[2], val, compare_op)); + insn = gen_addqi3_carry; break; case HImode: - emit_insn (gen_addhi3_carry (operands[0], operands[2], val, compare_op)); + insn = gen_addhi3_carry; break; case SImode: - emit_insn (gen_addsi3_carry (operands[0], operands[2], val, compare_op)); + insn = gen_addsi3_carry; break; case DImode: - emit_insn (gen_adddi3_carry_rex64 (operands[0], operands[2], val, compare_op)); + insn = gen_adddi3_carry; break; default: gcc_unreachable (); } } + emit_insn (insn (operands[0], operands[2], val, compare_op)); + return 1; /* DONE */ } @@ -19977,6 +20181,9 @@ ix86_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) } #ifdef ENABLE_EXECUTE_STACK +#ifdef CHECK_EXECUTE_STACK_ENABLED + if (CHECK_EXECUTE_STACK_ENABLED) +#endif emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"), LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode); #endif @@ -20712,7 +20919,7 @@ enum ix86_builtins IX86_BUILTIN_CVTUDQ2PS, - /* FMA4 instructions. */ + /* FMA4 and XOP instructions. */ IX86_BUILTIN_VFMADDSS, IX86_BUILTIN_VFMADDSD, IX86_BUILTIN_VFMADDPS, @@ -20745,6 +20952,164 @@ enum ix86_builtins IX86_BUILTIN_VFNMADDPD256, IX86_BUILTIN_VFNMSUBPS256, IX86_BUILTIN_VFNMSUBPD256, + + IX86_BUILTIN_VPCMOV, + IX86_BUILTIN_VPCMOV_V2DI, + IX86_BUILTIN_VPCMOV_V4SI, + IX86_BUILTIN_VPCMOV_V8HI, + IX86_BUILTIN_VPCMOV_V16QI, + IX86_BUILTIN_VPCMOV_V4SF, + IX86_BUILTIN_VPCMOV_V2DF, + IX86_BUILTIN_VPCMOV256, + IX86_BUILTIN_VPCMOV_V4DI256, + IX86_BUILTIN_VPCMOV_V8SI256, + IX86_BUILTIN_VPCMOV_V16HI256, + IX86_BUILTIN_VPCMOV_V32QI256, + IX86_BUILTIN_VPCMOV_V8SF256, + IX86_BUILTIN_VPCMOV_V4DF256, + + IX86_BUILTIN_VPPERM, + + IX86_BUILTIN_VPMACSSWW, + IX86_BUILTIN_VPMACSWW, + IX86_BUILTIN_VPMACSSWD, + IX86_BUILTIN_VPMACSWD, + IX86_BUILTIN_VPMACSSDD, + IX86_BUILTIN_VPMACSDD, + IX86_BUILTIN_VPMACSSDQL, + IX86_BUILTIN_VPMACSSDQH, + IX86_BUILTIN_VPMACSDQL, + IX86_BUILTIN_VPMACSDQH, + IX86_BUILTIN_VPMADCSSWD, + IX86_BUILTIN_VPMADCSWD, + + IX86_BUILTIN_VPHADDBW, + IX86_BUILTIN_VPHADDBD, + IX86_BUILTIN_VPHADDBQ, + IX86_BUILTIN_VPHADDWD, + IX86_BUILTIN_VPHADDWQ, + IX86_BUILTIN_VPHADDDQ, + IX86_BUILTIN_VPHADDUBW, + IX86_BUILTIN_VPHADDUBD, + IX86_BUILTIN_VPHADDUBQ, + IX86_BUILTIN_VPHADDUWD, + IX86_BUILTIN_VPHADDUWQ, + IX86_BUILTIN_VPHADDUDQ, + IX86_BUILTIN_VPHSUBBW, + IX86_BUILTIN_VPHSUBWD, + IX86_BUILTIN_VPHSUBDQ, + + IX86_BUILTIN_VPROTB, + IX86_BUILTIN_VPROTW, + IX86_BUILTIN_VPROTD, + IX86_BUILTIN_VPROTQ, + IX86_BUILTIN_VPROTB_IMM, + IX86_BUILTIN_VPROTW_IMM, + IX86_BUILTIN_VPROTD_IMM, + IX86_BUILTIN_VPROTQ_IMM, + + IX86_BUILTIN_VPSHLB, + IX86_BUILTIN_VPSHLW, + IX86_BUILTIN_VPSHLD, + IX86_BUILTIN_VPSHLQ, + IX86_BUILTIN_VPSHAB, + IX86_BUILTIN_VPSHAW, + IX86_BUILTIN_VPSHAD, + IX86_BUILTIN_VPSHAQ, + + IX86_BUILTIN_VFRCZSS, + IX86_BUILTIN_VFRCZSD, + IX86_BUILTIN_VFRCZPS, + IX86_BUILTIN_VFRCZPD, + IX86_BUILTIN_VFRCZPS256, + IX86_BUILTIN_VFRCZPD256, + + IX86_BUILTIN_VPCOMEQUB, + IX86_BUILTIN_VPCOMNEUB, + IX86_BUILTIN_VPCOMLTUB, + IX86_BUILTIN_VPCOMLEUB, + IX86_BUILTIN_VPCOMGTUB, + IX86_BUILTIN_VPCOMGEUB, + IX86_BUILTIN_VPCOMFALSEUB, + IX86_BUILTIN_VPCOMTRUEUB, + + IX86_BUILTIN_VPCOMEQUW, + IX86_BUILTIN_VPCOMNEUW, + IX86_BUILTIN_VPCOMLTUW, + IX86_BUILTIN_VPCOMLEUW, + IX86_BUILTIN_VPCOMGTUW, + IX86_BUILTIN_VPCOMGEUW, + IX86_BUILTIN_VPCOMFALSEUW, + IX86_BUILTIN_VPCOMTRUEUW, + + IX86_BUILTIN_VPCOMEQUD, + IX86_BUILTIN_VPCOMNEUD, + IX86_BUILTIN_VPCOMLTUD, + IX86_BUILTIN_VPCOMLEUD, + IX86_BUILTIN_VPCOMGTUD, + IX86_BUILTIN_VPCOMGEUD, + IX86_BUILTIN_VPCOMFALSEUD, + IX86_BUILTIN_VPCOMTRUEUD, + + IX86_BUILTIN_VPCOMEQUQ, + IX86_BUILTIN_VPCOMNEUQ, + IX86_BUILTIN_VPCOMLTUQ, + IX86_BUILTIN_VPCOMLEUQ, + IX86_BUILTIN_VPCOMGTUQ, + IX86_BUILTIN_VPCOMGEUQ, + IX86_BUILTIN_VPCOMFALSEUQ, + IX86_BUILTIN_VPCOMTRUEUQ, + + IX86_BUILTIN_VPCOMEQB, + IX86_BUILTIN_VPCOMNEB, + IX86_BUILTIN_VPCOMLTB, + IX86_BUILTIN_VPCOMLEB, + IX86_BUILTIN_VPCOMGTB, + IX86_BUILTIN_VPCOMGEB, + IX86_BUILTIN_VPCOMFALSEB, + IX86_BUILTIN_VPCOMTRUEB, + + IX86_BUILTIN_VPCOMEQW, + IX86_BUILTIN_VPCOMNEW, + IX86_BUILTIN_VPCOMLTW, + IX86_BUILTIN_VPCOMLEW, + IX86_BUILTIN_VPCOMGTW, + IX86_BUILTIN_VPCOMGEW, + IX86_BUILTIN_VPCOMFALSEW, + IX86_BUILTIN_VPCOMTRUEW, + + IX86_BUILTIN_VPCOMEQD, + IX86_BUILTIN_VPCOMNED, + IX86_BUILTIN_VPCOMLTD, + IX86_BUILTIN_VPCOMLED, + IX86_BUILTIN_VPCOMGTD, + IX86_BUILTIN_VPCOMGED, + IX86_BUILTIN_VPCOMFALSED, + IX86_BUILTIN_VPCOMTRUED, + + IX86_BUILTIN_VPCOMEQQ, + IX86_BUILTIN_VPCOMNEQ, + IX86_BUILTIN_VPCOMLTQ, + IX86_BUILTIN_VPCOMLEQ, + IX86_BUILTIN_VPCOMGTQ, + IX86_BUILTIN_VPCOMGEQ, + IX86_BUILTIN_VPCOMFALSEQ, + IX86_BUILTIN_VPCOMTRUEQ, + + /* LWP instructions. */ + IX86_BUILTIN_LLWPCB16, + IX86_BUILTIN_LLWPCB32, + IX86_BUILTIN_LLWPCB64, + IX86_BUILTIN_SLWPCB16, + IX86_BUILTIN_SLWPCB32, + IX86_BUILTIN_SLWPCB64, + IX86_BUILTIN_LWPVAL16, + IX86_BUILTIN_LWPVAL32, + IX86_BUILTIN_LWPVAL64, + IX86_BUILTIN_LWPINS16, + IX86_BUILTIN_LWPINS32, + IX86_BUILTIN_LWPINS64, + IX86_BUILTIN_MAX }; @@ -20958,7 +21323,13 @@ enum ix86_special_builtin_type VOID_FTYPE_PV8SF_V8SF_V8SF, VOID_FTYPE_PV4DF_V4DF_V4DF, VOID_FTYPE_PV4SF_V4SF_V4SF, - VOID_FTYPE_PV2DF_V2DF_V2DF + VOID_FTYPE_PV2DF_V2DF_V2DF, + VOID_FTYPE_USHORT_UINT_USHORT, + VOID_FTYPE_UINT_UINT_UINT, + VOID_FTYPE_UINT64_UINT_UINT, + UCHAR_FTYPE_USHORT_UINT_USHORT, + UCHAR_FTYPE_UINT_UINT_UINT, + UCHAR_FTYPE_UINT64_UINT_UINT }; /* Builtin types */ @@ -21205,6 +21576,22 @@ static const struct builtin_description bdesc_special_args[] = { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskstoreps, "__builtin_ia32_maskstoreps", IX86_BUILTIN_MASKSTOREPS, UNKNOWN, (int) VOID_FTYPE_PV4SF_V4SF_V4SF }, { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskstorepd256, "__builtin_ia32_maskstorepd256", IX86_BUILTIN_MASKSTOREPD256, UNKNOWN, (int) VOID_FTYPE_PV4DF_V4DF_V4DF }, { OPTION_MASK_ISA_AVX, CODE_FOR_avx_maskstoreps256, "__builtin_ia32_maskstoreps256", IX86_BUILTIN_MASKSTOREPS256, UNKNOWN, (int) VOID_FTYPE_PV8SF_V8SF_V8SF }, + + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_llwpcbhi1, "__builtin_ia32_llwpcb16", IX86_BUILTIN_LLWPCB16, UNKNOWN, (int) VOID_FTYPE_VOID }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_llwpcbsi1, "__builtin_ia32_llwpcb32", IX86_BUILTIN_LLWPCB32, UNKNOWN, (int) VOID_FTYPE_VOID }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_llwpcbdi1, "__builtin_ia32_llwpcb64", IX86_BUILTIN_LLWPCB64, UNKNOWN, (int) VOID_FTYPE_VOID }, + + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_slwpcbhi1, "__builtin_ia32_slwpcb16", IX86_BUILTIN_SLWPCB16, UNKNOWN, (int) VOID_FTYPE_VOID }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_slwpcbsi1, "__builtin_ia32_slwpcb32", IX86_BUILTIN_SLWPCB32, UNKNOWN, (int) VOID_FTYPE_VOID }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_slwpcbdi1, "__builtin_ia32_slwpcb64", IX86_BUILTIN_SLWPCB64, UNKNOWN, (int) VOID_FTYPE_VOID }, + + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_lwpvalhi3, "__builtin_ia32_lwpval16", IX86_BUILTIN_LWPVAL16, UNKNOWN, (int) VOID_FTYPE_USHORT_UINT_USHORT }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_lwpvalsi3, "__builtin_ia32_lwpval32", IX86_BUILTIN_LWPVAL64, UNKNOWN, (int) VOID_FTYPE_UINT_UINT_UINT }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_lwpvaldi3, "__builtin_ia32_lwpval64", IX86_BUILTIN_LWPVAL64, UNKNOWN, (int) VOID_FTYPE_UINT64_UINT_UINT }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_lwpinshi3, "__builtin_ia32_lwpins16", IX86_BUILTIN_LWPINS16, UNKNOWN, (int) UCHAR_FTYPE_USHORT_UINT_USHORT }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_lwpinssi3, "__builtin_ia32_lwpins32", IX86_BUILTIN_LWPINS64, UNKNOWN, (int) UCHAR_FTYPE_UINT_UINT_UINT }, + { OPTION_MASK_ISA_LWP, CODE_FOR_lwp_lwpinsdi3, "__builtin_ia32_lwpins64", IX86_BUILTIN_LWPINS64, UNKNOWN, (int) UCHAR_FTYPE_UINT64_UINT_UINT }, + }; /* Builtins with variable number of arguments. */ @@ -21818,13 +22205,58 @@ static const struct builtin_description bdesc_args[] = { OPTION_MASK_ISA_AVX, CODE_FOR_avx_movmskps256, "__builtin_ia32_movmskps256", IX86_BUILTIN_MOVMSKPS256, UNKNOWN, (int) INT_FTYPE_V8SF }, }; -/* FMA4. */ +/* FMA4 and XOP. */ enum multi_arg_type { MULTI_ARG_UNKNOWN, MULTI_ARG_3_SF, MULTI_ARG_3_DF, MULTI_ARG_3_SF2, - MULTI_ARG_3_DF2 + MULTI_ARG_3_DF2, + MULTI_ARG_3_DI, + MULTI_ARG_3_SI, + MULTI_ARG_3_SI_DI, + MULTI_ARG_3_HI, + MULTI_ARG_3_HI_SI, + MULTI_ARG_3_QI, + MULTI_ARG_3_DI2, + MULTI_ARG_3_SI2, + MULTI_ARG_3_HI2, + MULTI_ARG_3_QI2, + MULTI_ARG_2_SF, + MULTI_ARG_2_DF, + MULTI_ARG_2_DI, + MULTI_ARG_2_SI, + MULTI_ARG_2_HI, + MULTI_ARG_2_QI, + MULTI_ARG_2_DI_IMM, + MULTI_ARG_2_SI_IMM, + MULTI_ARG_2_HI_IMM, + MULTI_ARG_2_QI_IMM, + MULTI_ARG_2_DI_CMP, + MULTI_ARG_2_SI_CMP, + MULTI_ARG_2_HI_CMP, + MULTI_ARG_2_QI_CMP, + MULTI_ARG_2_DI_TF, + MULTI_ARG_2_SI_TF, + MULTI_ARG_2_HI_TF, + MULTI_ARG_2_QI_TF, + MULTI_ARG_2_SF_TF, + MULTI_ARG_2_DF_TF, + MULTI_ARG_1_SF, + MULTI_ARG_1_DF, + MULTI_ARG_1_SF2, + MULTI_ARG_1_DF2, + MULTI_ARG_1_DI, + MULTI_ARG_1_SI, + MULTI_ARG_1_HI, + MULTI_ARG_1_QI, + MULTI_ARG_1_SI_DI, + MULTI_ARG_1_HI_DI, + MULTI_ARG_1_HI_SI, + MULTI_ARG_1_QI_DI, + MULTI_ARG_1_QI_SI, + MULTI_ARG_1_QI_HI + }; static const struct builtin_description bdesc_multi_arg[] = @@ -21865,7 +22297,160 @@ static const struct builtin_description bdesc_multi_arg[] = { OPTION_MASK_ISA_FMA4, CODE_FOR_fma4i_fmaddsubv8sf4, "__builtin_ia32_vfmaddsubps256", IX86_BUILTIN_VFMADDSUBPS256, UNKNOWN, (int)MULTI_ARG_3_SF2 }, { OPTION_MASK_ISA_FMA4, CODE_FOR_fma4i_fmaddsubv4df4, "__builtin_ia32_vfmaddsubpd256", IX86_BUILTIN_VFMADDSUBPD256, UNKNOWN, (int)MULTI_ARG_3_DF2 }, { OPTION_MASK_ISA_FMA4, CODE_FOR_fma4i_fmsubaddv8sf4, "__builtin_ia32_vfmsubaddps256", IX86_BUILTIN_VFMSUBADDPS256, UNKNOWN, (int)MULTI_ARG_3_SF2 }, - { OPTION_MASK_ISA_FMA4, CODE_FOR_fma4i_fmsubaddv4df4, "__builtin_ia32_vfmsubaddpd256", IX86_BUILTIN_VFMSUBADDPD256, UNKNOWN, (int)MULTI_ARG_3_DF2 } + { OPTION_MASK_ISA_FMA4, CODE_FOR_fma4i_fmsubaddv4df4, "__builtin_ia32_vfmsubaddpd256", IX86_BUILTIN_VFMSUBADDPD256, UNKNOWN, (int)MULTI_ARG_3_DF2 }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v2di, "__builtin_ia32_vpcmov", IX86_BUILTIN_VPCMOV, UNKNOWN, (int)MULTI_ARG_3_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v2di, "__builtin_ia32_vpcmov_v2di", IX86_BUILTIN_VPCMOV_V2DI, UNKNOWN, (int)MULTI_ARG_3_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v4si, "__builtin_ia32_vpcmov_v4si", IX86_BUILTIN_VPCMOV_V4SI, UNKNOWN, (int)MULTI_ARG_3_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v8hi, "__builtin_ia32_vpcmov_v8hi", IX86_BUILTIN_VPCMOV_V8HI, UNKNOWN, (int)MULTI_ARG_3_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v16qi, "__builtin_ia32_vpcmov_v16qi",IX86_BUILTIN_VPCMOV_V16QI,UNKNOWN, (int)MULTI_ARG_3_QI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v2df, "__builtin_ia32_vpcmov_v2df", IX86_BUILTIN_VPCMOV_V2DF, UNKNOWN, (int)MULTI_ARG_3_DF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v4sf, "__builtin_ia32_vpcmov_v4sf", IX86_BUILTIN_VPCMOV_V4SF, UNKNOWN, (int)MULTI_ARG_3_SF }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v4di256, "__builtin_ia32_vpcmov256", IX86_BUILTIN_VPCMOV256, UNKNOWN, (int)MULTI_ARG_3_DI2 }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v4di256, "__builtin_ia32_vpcmov_v4di256", IX86_BUILTIN_VPCMOV_V4DI256, UNKNOWN, (int)MULTI_ARG_3_DI2 }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v8si256, "__builtin_ia32_vpcmov_v8si256", IX86_BUILTIN_VPCMOV_V8SI256, UNKNOWN, (int)MULTI_ARG_3_SI2 }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v16hi256, "__builtin_ia32_vpcmov_v16hi256", IX86_BUILTIN_VPCMOV_V16HI256, UNKNOWN, (int)MULTI_ARG_3_HI2 }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v32qi256, "__builtin_ia32_vpcmov_v32qi256", IX86_BUILTIN_VPCMOV_V32QI256, UNKNOWN, (int)MULTI_ARG_3_QI2 }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v4df256, "__builtin_ia32_vpcmov_v4df256", IX86_BUILTIN_VPCMOV_V4DF256, UNKNOWN, (int)MULTI_ARG_3_DF2 }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcmov_v8sf256, "__builtin_ia32_vpcmov_v8sf256", IX86_BUILTIN_VPCMOV_V8SF256, UNKNOWN, (int)MULTI_ARG_3_SF2 }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pperm, "__builtin_ia32_vpperm", IX86_BUILTIN_VPPERM, UNKNOWN, (int)MULTI_ARG_3_QI }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacssww, "__builtin_ia32_vpmacssww", IX86_BUILTIN_VPMACSSWW, UNKNOWN, (int)MULTI_ARG_3_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacsww, "__builtin_ia32_vpmacsww", IX86_BUILTIN_VPMACSWW, UNKNOWN, (int)MULTI_ARG_3_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacsswd, "__builtin_ia32_vpmacsswd", IX86_BUILTIN_VPMACSSWD, UNKNOWN, (int)MULTI_ARG_3_HI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacswd, "__builtin_ia32_vpmacswd", IX86_BUILTIN_VPMACSWD, UNKNOWN, (int)MULTI_ARG_3_HI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacssdd, "__builtin_ia32_vpmacssdd", IX86_BUILTIN_VPMACSSDD, UNKNOWN, (int)MULTI_ARG_3_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacsdd, "__builtin_ia32_vpmacsdd", IX86_BUILTIN_VPMACSDD, UNKNOWN, (int)MULTI_ARG_3_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacssdql, "__builtin_ia32_vpmacssdql", IX86_BUILTIN_VPMACSSDQL, UNKNOWN, (int)MULTI_ARG_3_SI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacssdqh, "__builtin_ia32_vpmacssdqh", IX86_BUILTIN_VPMACSSDQH, UNKNOWN, (int)MULTI_ARG_3_SI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacsdql, "__builtin_ia32_vpmacsdql", IX86_BUILTIN_VPMACSDQL, UNKNOWN, (int)MULTI_ARG_3_SI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmacsdqh, "__builtin_ia32_vpmacsdqh", IX86_BUILTIN_VPMACSDQH, UNKNOWN, (int)MULTI_ARG_3_SI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmadcsswd, "__builtin_ia32_vpmadcsswd", IX86_BUILTIN_VPMADCSSWD, UNKNOWN, (int)MULTI_ARG_3_HI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pmadcswd, "__builtin_ia32_vpmadcswd", IX86_BUILTIN_VPMADCSWD, UNKNOWN, (int)MULTI_ARG_3_HI_SI }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vrotlv2di3, "__builtin_ia32_vprotq", IX86_BUILTIN_VPROTQ, UNKNOWN, (int)MULTI_ARG_2_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vrotlv4si3, "__builtin_ia32_vprotd", IX86_BUILTIN_VPROTD, UNKNOWN, (int)MULTI_ARG_2_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vrotlv8hi3, "__builtin_ia32_vprotw", IX86_BUILTIN_VPROTW, UNKNOWN, (int)MULTI_ARG_2_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vrotlv16qi3, "__builtin_ia32_vprotb", IX86_BUILTIN_VPROTB, UNKNOWN, (int)MULTI_ARG_2_QI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_rotlv2di3, "__builtin_ia32_vprotqi", IX86_BUILTIN_VPROTQ_IMM, UNKNOWN, (int)MULTI_ARG_2_DI_IMM }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_rotlv4si3, "__builtin_ia32_vprotdi", IX86_BUILTIN_VPROTD_IMM, UNKNOWN, (int)MULTI_ARG_2_SI_IMM }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_rotlv8hi3, "__builtin_ia32_vprotwi", IX86_BUILTIN_VPROTW_IMM, UNKNOWN, (int)MULTI_ARG_2_HI_IMM }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_rotlv16qi3, "__builtin_ia32_vprotbi", IX86_BUILTIN_VPROTB_IMM, UNKNOWN, (int)MULTI_ARG_2_QI_IMM }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_ashlv2di3, "__builtin_ia32_vpshaq", IX86_BUILTIN_VPSHAQ, UNKNOWN, (int)MULTI_ARG_2_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_ashlv4si3, "__builtin_ia32_vpshad", IX86_BUILTIN_VPSHAD, UNKNOWN, (int)MULTI_ARG_2_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_ashlv8hi3, "__builtin_ia32_vpshaw", IX86_BUILTIN_VPSHAW, UNKNOWN, (int)MULTI_ARG_2_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_ashlv16qi3, "__builtin_ia32_vpshab", IX86_BUILTIN_VPSHAB, UNKNOWN, (int)MULTI_ARG_2_QI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_lshlv2di3, "__builtin_ia32_vpshlq", IX86_BUILTIN_VPSHLQ, UNKNOWN, (int)MULTI_ARG_2_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_lshlv4si3, "__builtin_ia32_vpshld", IX86_BUILTIN_VPSHLD, UNKNOWN, (int)MULTI_ARG_2_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_lshlv8hi3, "__builtin_ia32_vpshlw", IX86_BUILTIN_VPSHLW, UNKNOWN, (int)MULTI_ARG_2_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_lshlv16qi3, "__builtin_ia32_vpshlb", IX86_BUILTIN_VPSHLB, UNKNOWN, (int)MULTI_ARG_2_QI }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vmfrczv4sf2, "__builtin_ia32_vfrczss", IX86_BUILTIN_VFRCZSS, UNKNOWN, (int)MULTI_ARG_2_SF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_vmfrczv2df2, "__builtin_ia32_vfrczsd", IX86_BUILTIN_VFRCZSD, UNKNOWN, (int)MULTI_ARG_2_DF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_frczv4sf2, "__builtin_ia32_vfrczps", IX86_BUILTIN_VFRCZPS, UNKNOWN, (int)MULTI_ARG_1_SF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_frczv2df2, "__builtin_ia32_vfrczpd", IX86_BUILTIN_VFRCZPD, UNKNOWN, (int)MULTI_ARG_1_DF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_frczv8sf2256, "__builtin_ia32_vfrczps256", IX86_BUILTIN_VFRCZPS256, UNKNOWN, (int)MULTI_ARG_1_SF2 }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_frczv4df2256, "__builtin_ia32_vfrczpd256", IX86_BUILTIN_VFRCZPD256, UNKNOWN, (int)MULTI_ARG_1_DF2 }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddbw, "__builtin_ia32_vphaddbw", IX86_BUILTIN_VPHADDBW, UNKNOWN, (int)MULTI_ARG_1_QI_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddbd, "__builtin_ia32_vphaddbd", IX86_BUILTIN_VPHADDBD, UNKNOWN, (int)MULTI_ARG_1_QI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddbq, "__builtin_ia32_vphaddbq", IX86_BUILTIN_VPHADDBQ, UNKNOWN, (int)MULTI_ARG_1_QI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddwd, "__builtin_ia32_vphaddwd", IX86_BUILTIN_VPHADDWD, UNKNOWN, (int)MULTI_ARG_1_HI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddwq, "__builtin_ia32_vphaddwq", IX86_BUILTIN_VPHADDWQ, UNKNOWN, (int)MULTI_ARG_1_HI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phadddq, "__builtin_ia32_vphadddq", IX86_BUILTIN_VPHADDDQ, UNKNOWN, (int)MULTI_ARG_1_SI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddubw, "__builtin_ia32_vphaddubw", IX86_BUILTIN_VPHADDUBW, UNKNOWN, (int)MULTI_ARG_1_QI_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddubd, "__builtin_ia32_vphaddubd", IX86_BUILTIN_VPHADDUBD, UNKNOWN, (int)MULTI_ARG_1_QI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddubq, "__builtin_ia32_vphaddubq", IX86_BUILTIN_VPHADDUBQ, UNKNOWN, (int)MULTI_ARG_1_QI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phadduwd, "__builtin_ia32_vphadduwd", IX86_BUILTIN_VPHADDUWD, UNKNOWN, (int)MULTI_ARG_1_HI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phadduwq, "__builtin_ia32_vphadduwq", IX86_BUILTIN_VPHADDUWQ, UNKNOWN, (int)MULTI_ARG_1_HI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phaddudq, "__builtin_ia32_vphaddudq", IX86_BUILTIN_VPHADDUDQ, UNKNOWN, (int)MULTI_ARG_1_SI_DI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phsubbw, "__builtin_ia32_vphsubbw", IX86_BUILTIN_VPHSUBBW, UNKNOWN, (int)MULTI_ARG_1_QI_HI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phsubwd, "__builtin_ia32_vphsubwd", IX86_BUILTIN_VPHSUBWD, UNKNOWN, (int)MULTI_ARG_1_HI_SI }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_phsubdq, "__builtin_ia32_vphsubdq", IX86_BUILTIN_VPHSUBDQ, UNKNOWN, (int)MULTI_ARG_1_SI_DI }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv16qi3, "__builtin_ia32_vpcomeqb", IX86_BUILTIN_VPCOMEQB, EQ, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv16qi3, "__builtin_ia32_vpcomneb", IX86_BUILTIN_VPCOMNEB, NE, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv16qi3, "__builtin_ia32_vpcomneqb", IX86_BUILTIN_VPCOMNEB, NE, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv16qi3, "__builtin_ia32_vpcomltb", IX86_BUILTIN_VPCOMLTB, LT, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv16qi3, "__builtin_ia32_vpcomleb", IX86_BUILTIN_VPCOMLEB, LE, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv16qi3, "__builtin_ia32_vpcomgtb", IX86_BUILTIN_VPCOMGTB, GT, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv16qi3, "__builtin_ia32_vpcomgeb", IX86_BUILTIN_VPCOMGEB, GE, (int)MULTI_ARG_2_QI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv8hi3, "__builtin_ia32_vpcomeqw", IX86_BUILTIN_VPCOMEQW, EQ, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv8hi3, "__builtin_ia32_vpcomnew", IX86_BUILTIN_VPCOMNEW, NE, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv8hi3, "__builtin_ia32_vpcomneqw", IX86_BUILTIN_VPCOMNEW, NE, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv8hi3, "__builtin_ia32_vpcomltw", IX86_BUILTIN_VPCOMLTW, LT, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv8hi3, "__builtin_ia32_vpcomlew", IX86_BUILTIN_VPCOMLEW, LE, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv8hi3, "__builtin_ia32_vpcomgtw", IX86_BUILTIN_VPCOMGTW, GT, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv8hi3, "__builtin_ia32_vpcomgew", IX86_BUILTIN_VPCOMGEW, GE, (int)MULTI_ARG_2_HI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv4si3, "__builtin_ia32_vpcomeqd", IX86_BUILTIN_VPCOMEQD, EQ, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv4si3, "__builtin_ia32_vpcomned", IX86_BUILTIN_VPCOMNED, NE, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv4si3, "__builtin_ia32_vpcomneqd", IX86_BUILTIN_VPCOMNED, NE, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv4si3, "__builtin_ia32_vpcomltd", IX86_BUILTIN_VPCOMLTD, LT, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv4si3, "__builtin_ia32_vpcomled", IX86_BUILTIN_VPCOMLED, LE, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv4si3, "__builtin_ia32_vpcomgtd", IX86_BUILTIN_VPCOMGTD, GT, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv4si3, "__builtin_ia32_vpcomged", IX86_BUILTIN_VPCOMGED, GE, (int)MULTI_ARG_2_SI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv2di3, "__builtin_ia32_vpcomeqq", IX86_BUILTIN_VPCOMEQQ, EQ, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv2di3, "__builtin_ia32_vpcomneq", IX86_BUILTIN_VPCOMNEQ, NE, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv2di3, "__builtin_ia32_vpcomneqq", IX86_BUILTIN_VPCOMNEQ, NE, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv2di3, "__builtin_ia32_vpcomltq", IX86_BUILTIN_VPCOMLTQ, LT, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv2di3, "__builtin_ia32_vpcomleq", IX86_BUILTIN_VPCOMLEQ, LE, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv2di3, "__builtin_ia32_vpcomgtq", IX86_BUILTIN_VPCOMGTQ, GT, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmpv2di3, "__builtin_ia32_vpcomgeq", IX86_BUILTIN_VPCOMGEQ, GE, (int)MULTI_ARG_2_DI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v16qi3,"__builtin_ia32_vpcomequb", IX86_BUILTIN_VPCOMEQUB, EQ, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v16qi3,"__builtin_ia32_vpcomneub", IX86_BUILTIN_VPCOMNEUB, NE, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v16qi3,"__builtin_ia32_vpcomnequb", IX86_BUILTIN_VPCOMNEUB, NE, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv16qi3, "__builtin_ia32_vpcomltub", IX86_BUILTIN_VPCOMLTUB, LTU, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv16qi3, "__builtin_ia32_vpcomleub", IX86_BUILTIN_VPCOMLEUB, LEU, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv16qi3, "__builtin_ia32_vpcomgtub", IX86_BUILTIN_VPCOMGTUB, GTU, (int)MULTI_ARG_2_QI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv16qi3, "__builtin_ia32_vpcomgeub", IX86_BUILTIN_VPCOMGEUB, GEU, (int)MULTI_ARG_2_QI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v8hi3, "__builtin_ia32_vpcomequw", IX86_BUILTIN_VPCOMEQUW, EQ, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v8hi3, "__builtin_ia32_vpcomneuw", IX86_BUILTIN_VPCOMNEUW, NE, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v8hi3, "__builtin_ia32_vpcomnequw", IX86_BUILTIN_VPCOMNEUW, NE, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv8hi3, "__builtin_ia32_vpcomltuw", IX86_BUILTIN_VPCOMLTUW, LTU, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv8hi3, "__builtin_ia32_vpcomleuw", IX86_BUILTIN_VPCOMLEUW, LEU, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv8hi3, "__builtin_ia32_vpcomgtuw", IX86_BUILTIN_VPCOMGTUW, GTU, (int)MULTI_ARG_2_HI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv8hi3, "__builtin_ia32_vpcomgeuw", IX86_BUILTIN_VPCOMGEUW, GEU, (int)MULTI_ARG_2_HI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v4si3, "__builtin_ia32_vpcomequd", IX86_BUILTIN_VPCOMEQUD, EQ, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v4si3, "__builtin_ia32_vpcomneud", IX86_BUILTIN_VPCOMNEUD, NE, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v4si3, "__builtin_ia32_vpcomnequd", IX86_BUILTIN_VPCOMNEUD, NE, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv4si3, "__builtin_ia32_vpcomltud", IX86_BUILTIN_VPCOMLTUD, LTU, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv4si3, "__builtin_ia32_vpcomleud", IX86_BUILTIN_VPCOMLEUD, LEU, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv4si3, "__builtin_ia32_vpcomgtud", IX86_BUILTIN_VPCOMGTUD, GTU, (int)MULTI_ARG_2_SI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv4si3, "__builtin_ia32_vpcomgeud", IX86_BUILTIN_VPCOMGEUD, GEU, (int)MULTI_ARG_2_SI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v2di3, "__builtin_ia32_vpcomequq", IX86_BUILTIN_VPCOMEQUQ, EQ, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v2di3, "__builtin_ia32_vpcomneuq", IX86_BUILTIN_VPCOMNEUQ, NE, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_uns2v2di3, "__builtin_ia32_vpcomnequq", IX86_BUILTIN_VPCOMNEUQ, NE, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv2di3, "__builtin_ia32_vpcomltuq", IX86_BUILTIN_VPCOMLTUQ, LTU, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv2di3, "__builtin_ia32_vpcomleuq", IX86_BUILTIN_VPCOMLEUQ, LEU, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv2di3, "__builtin_ia32_vpcomgtuq", IX86_BUILTIN_VPCOMGTUQ, GTU, (int)MULTI_ARG_2_DI_CMP }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_maskcmp_unsv2di3, "__builtin_ia32_vpcomgeuq", IX86_BUILTIN_VPCOMGEUQ, GEU, (int)MULTI_ARG_2_DI_CMP }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv16qi3, "__builtin_ia32_vpcomfalseb", IX86_BUILTIN_VPCOMFALSEB, (enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_QI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv8hi3, "__builtin_ia32_vpcomfalsew", IX86_BUILTIN_VPCOMFALSEW, (enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_HI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv4si3, "__builtin_ia32_vpcomfalsed", IX86_BUILTIN_VPCOMFALSED, (enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_SI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv2di3, "__builtin_ia32_vpcomfalseq", IX86_BUILTIN_VPCOMFALSEQ, (enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_DI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv16qi3, "__builtin_ia32_vpcomfalseub",IX86_BUILTIN_VPCOMFALSEUB,(enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_QI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv8hi3, "__builtin_ia32_vpcomfalseuw",IX86_BUILTIN_VPCOMFALSEUW,(enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_HI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv4si3, "__builtin_ia32_vpcomfalseud",IX86_BUILTIN_VPCOMFALSEUD,(enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_SI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv2di3, "__builtin_ia32_vpcomfalseuq",IX86_BUILTIN_VPCOMFALSEUQ,(enum rtx_code) PCOM_FALSE, (int)MULTI_ARG_2_DI_TF }, + + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv16qi3, "__builtin_ia32_vpcomtrueb", IX86_BUILTIN_VPCOMTRUEB, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_QI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv8hi3, "__builtin_ia32_vpcomtruew", IX86_BUILTIN_VPCOMTRUEW, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_HI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv4si3, "__builtin_ia32_vpcomtrued", IX86_BUILTIN_VPCOMTRUED, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_SI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv2di3, "__builtin_ia32_vpcomtrueq", IX86_BUILTIN_VPCOMTRUEQ, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_DI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv16qi3, "__builtin_ia32_vpcomtrueub", IX86_BUILTIN_VPCOMTRUEUB, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_QI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv8hi3, "__builtin_ia32_vpcomtrueuw", IX86_BUILTIN_VPCOMTRUEUW, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_HI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv4si3, "__builtin_ia32_vpcomtrueud", IX86_BUILTIN_VPCOMTRUEUD, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_SI_TF }, + { OPTION_MASK_ISA_XOP, CODE_FOR_xop_pcom_tfv2di3, "__builtin_ia32_vpcomtrueuq", IX86_BUILTIN_VPCOMTRUEUQ, (enum rtx_code) PCOM_TRUE, (int)MULTI_ARG_2_DI_TF }, }; @@ -22247,51 +22832,6 @@ ix86_init_mmx_sse_builtins (void) integer_type_node, NULL_TREE); - - tree v2di_ftype_v2di - = build_function_type_list (V2DI_type_node, V2DI_type_node, NULL_TREE); - - tree v16qi_ftype_v8hi_v8hi - = build_function_type_list (V16QI_type_node, - V8HI_type_node, V8HI_type_node, - NULL_TREE); - tree v8hi_ftype_v4si_v4si - = build_function_type_list (V8HI_type_node, - V4SI_type_node, V4SI_type_node, - NULL_TREE); - tree v8hi_ftype_v16qi_v16qi - = build_function_type_list (V8HI_type_node, - V16QI_type_node, V16QI_type_node, - NULL_TREE); - tree v4hi_ftype_v8qi_v8qi - = build_function_type_list (V4HI_type_node, - V8QI_type_node, V8QI_type_node, - NULL_TREE); - tree unsigned_ftype_unsigned_uchar - = build_function_type_list (unsigned_type_node, - unsigned_type_node, - unsigned_char_type_node, - NULL_TREE); - tree unsigned_ftype_unsigned_ushort - = build_function_type_list (unsigned_type_node, - unsigned_type_node, - short_unsigned_type_node, - NULL_TREE); - tree unsigned_ftype_unsigned_unsigned - = build_function_type_list (unsigned_type_node, - unsigned_type_node, - unsigned_type_node, - NULL_TREE); - tree uint64_ftype_uint64_uint64 - = build_function_type_list (long_long_unsigned_type_node, - long_long_unsigned_type_node, - long_long_unsigned_type_node, - NULL_TREE); - tree float_ftype_float - = build_function_type_list (float_type_node, - float_type_node, - NULL_TREE); - /* AVX builtins */ tree V32QI_type_node = build_vector_type_for_mode (char_type_node, V32QImode); @@ -22303,6 +22843,8 @@ ix86_init_mmx_sse_builtins (void) V4DImode); tree V4DF_type_node = build_vector_type_for_mode (double_type_node, V4DFmode); + tree V16HI_type_node = build_vector_type_for_mode (intHI_type_node, + V16HImode); tree v8sf_ftype_v8sf = build_function_type_list (V8SF_type_node, V8SF_type_node, @@ -22547,6 +23089,138 @@ ix86_init_mmx_sse_builtins (void) = build_function_type_list (V2DF_type_node, V2DF_type_node, V2DI_type_node, NULL_TREE); + /* XOP instructions */ + tree v2di_ftype_v2di_v2di_v2di + = build_function_type_list (V2DI_type_node, + V2DI_type_node, + V2DI_type_node, + V2DI_type_node, + NULL_TREE); + + tree v4di_ftype_v4di_v4di_v4di + = build_function_type_list (V4DI_type_node, + V4DI_type_node, + V4DI_type_node, + V4DI_type_node, + NULL_TREE); + + tree v4si_ftype_v4si_v4si_v4si + = build_function_type_list (V4SI_type_node, + V4SI_type_node, + V4SI_type_node, + V4SI_type_node, + NULL_TREE); + + tree v8si_ftype_v8si_v8si_v8si + = build_function_type_list (V8SI_type_node, + V8SI_type_node, + V8SI_type_node, + V8SI_type_node, + NULL_TREE); + + tree v32qi_ftype_v32qi_v32qi_v32qi + = build_function_type_list (V32QI_type_node, + V32QI_type_node, + V32QI_type_node, + V32QI_type_node, + NULL_TREE); + + tree v4si_ftype_v4si_v4si_v2di + = build_function_type_list (V4SI_type_node, + V4SI_type_node, + V4SI_type_node, + V2DI_type_node, + NULL_TREE); + + tree v8hi_ftype_v8hi_v8hi_v8hi + = build_function_type_list (V8HI_type_node, + V8HI_type_node, + V8HI_type_node, + V8HI_type_node, + NULL_TREE); + + tree v16hi_ftype_v16hi_v16hi_v16hi + = build_function_type_list (V16HI_type_node, + V16HI_type_node, + V16HI_type_node, + V16HI_type_node, + NULL_TREE); + + tree v8hi_ftype_v8hi_v8hi_v4si + = build_function_type_list (V8HI_type_node, + V8HI_type_node, + V8HI_type_node, + V4SI_type_node, + NULL_TREE); + + tree v2di_ftype_v2di_si + = build_function_type_list (V2DI_type_node, + V2DI_type_node, + integer_type_node, + NULL_TREE); + + tree v4si_ftype_v4si_si + = build_function_type_list (V4SI_type_node, + V4SI_type_node, + integer_type_node, + NULL_TREE); + + tree v8hi_ftype_v8hi_si + = build_function_type_list (V8HI_type_node, + V8HI_type_node, + integer_type_node, + NULL_TREE); + + tree v16qi_ftype_v16qi_si + = build_function_type_list (V16QI_type_node, + V16QI_type_node, + integer_type_node, + NULL_TREE); + + tree v2di_ftype_v2di + = build_function_type_list (V2DI_type_node, V2DI_type_node, NULL_TREE); + + tree v16qi_ftype_v8hi_v8hi + = build_function_type_list (V16QI_type_node, + V8HI_type_node, V8HI_type_node, + NULL_TREE); + tree v8hi_ftype_v4si_v4si + = build_function_type_list (V8HI_type_node, + V4SI_type_node, V4SI_type_node, + NULL_TREE); + tree v8hi_ftype_v16qi_v16qi + = build_function_type_list (V8HI_type_node, + V16QI_type_node, V16QI_type_node, + NULL_TREE); + tree v4hi_ftype_v8qi_v8qi + = build_function_type_list (V4HI_type_node, + V8QI_type_node, V8QI_type_node, + NULL_TREE); + tree unsigned_ftype_unsigned_uchar + = build_function_type_list (unsigned_type_node, + unsigned_type_node, + unsigned_char_type_node, + NULL_TREE); + tree unsigned_ftype_unsigned_ushort + = build_function_type_list (unsigned_type_node, + unsigned_type_node, + short_unsigned_type_node, + NULL_TREE); + tree unsigned_ftype_unsigned_unsigned + = build_function_type_list (unsigned_type_node, + unsigned_type_node, + unsigned_type_node, + NULL_TREE); + tree uint64_ftype_uint64_uint64 + = build_function_type_list (long_long_unsigned_type_node, + long_long_unsigned_type_node, + long_long_unsigned_type_node, + NULL_TREE); + tree float_ftype_float + = build_function_type_list (float_type_node, + float_type_node, + NULL_TREE); + /* Integer intrinsics. */ tree uint64_ftype_void = build_function_type (long_long_unsigned_type_node, @@ -22576,6 +23250,50 @@ ix86_init_mmx_sse_builtins (void) integer_type_node, NULL_TREE); + /* LWP instructions. */ + + tree void_ftype_ushort_unsigned_ushort + = build_function_type_list (void_type_node, + short_unsigned_type_node, + unsigned_type_node, + short_unsigned_type_node, + NULL_TREE); + + tree void_ftype_unsigned_unsigned_unsigned + = build_function_type_list (void_type_node, + unsigned_type_node, + unsigned_type_node, + unsigned_type_node, + NULL_TREE); + + tree void_ftype_uint64_unsigned_unsigned + = build_function_type_list (void_type_node, + long_long_unsigned_type_node, + unsigned_type_node, + unsigned_type_node, + NULL_TREE); + + tree uchar_ftype_ushort_unsigned_ushort + = build_function_type_list (unsigned_char_type_node, + short_unsigned_type_node, + unsigned_type_node, + short_unsigned_type_node, + NULL_TREE); + + tree uchar_ftype_unsigned_unsigned_unsigned + = build_function_type_list (unsigned_char_type_node, + unsigned_type_node, + unsigned_type_node, + unsigned_type_node, + NULL_TREE); + + tree uchar_ftype_uint64_unsigned_unsigned + = build_function_type_list (unsigned_char_type_node, + long_long_unsigned_type_node, + unsigned_type_node, + unsigned_type_node, + NULL_TREE); + tree ftype; /* Add all special builtins with variable number of operands. */ @@ -22689,6 +23407,25 @@ ix86_init_mmx_sse_builtins (void) case VOID_FTYPE_PV2DF_V2DF_V2DF: type = void_ftype_pv2df_v2df_v2df; break; + case VOID_FTYPE_USHORT_UINT_USHORT: + type = void_ftype_ushort_unsigned_ushort; + break; + case VOID_FTYPE_UINT_UINT_UINT: + type = void_ftype_unsigned_unsigned_unsigned; + break; + case VOID_FTYPE_UINT64_UINT_UINT: + type = void_ftype_uint64_unsigned_unsigned; + break; + case UCHAR_FTYPE_USHORT_UINT_USHORT: + type = uchar_ftype_ushort_unsigned_ushort; + break; + case UCHAR_FTYPE_UINT_UINT_UINT: + type = uchar_ftype_unsigned_unsigned_unsigned; + break; + case UCHAR_FTYPE_UINT64_UINT_UINT: + type = uchar_ftype_uint64_unsigned_unsigned; + break; + default: gcc_unreachable (); } @@ -23315,6 +24052,50 @@ ix86_init_mmx_sse_builtins (void) case MULTI_ARG_3_DF: mtype = v2df_ftype_v2df_v2df_v2df; break; case MULTI_ARG_3_SF2: mtype = v8sf_ftype_v8sf_v8sf_v8sf; break; case MULTI_ARG_3_DF2: mtype = v4df_ftype_v4df_v4df_v4df; break; + case MULTI_ARG_3_DI: mtype = v2di_ftype_v2di_v2di_v2di; break; + case MULTI_ARG_3_SI: mtype = v4si_ftype_v4si_v4si_v4si; break; + case MULTI_ARG_3_SI_DI: mtype = v4si_ftype_v4si_v4si_v2di; break; + case MULTI_ARG_3_HI: mtype = v8hi_ftype_v8hi_v8hi_v8hi; break; + case MULTI_ARG_3_HI_SI: mtype = v8hi_ftype_v8hi_v8hi_v4si; break; + case MULTI_ARG_3_QI: mtype = v16qi_ftype_v16qi_v16qi_v16qi; break; + case MULTI_ARG_3_DI2: mtype = v4di_ftype_v4di_v4di_v4di; break; + case MULTI_ARG_3_SI2: mtype = v8si_ftype_v8si_v8si_v8si; break; + case MULTI_ARG_3_HI2: mtype = v16hi_ftype_v16hi_v16hi_v16hi; break; + case MULTI_ARG_3_QI2: mtype = v32qi_ftype_v32qi_v32qi_v32qi; break; + case MULTI_ARG_2_SF: mtype = v4sf_ftype_v4sf_v4sf; break; + case MULTI_ARG_2_DF: mtype = v2df_ftype_v2df_v2df; break; + case MULTI_ARG_2_DI: mtype = v2di_ftype_v2di_v2di; break; + case MULTI_ARG_2_SI: mtype = v4si_ftype_v4si_v4si; break; + case MULTI_ARG_2_HI: mtype = v8hi_ftype_v8hi_v8hi; break; + case MULTI_ARG_2_QI: mtype = v16qi_ftype_v16qi_v16qi; break; + case MULTI_ARG_2_DI_IMM: mtype = v2di_ftype_v2di_si; break; + case MULTI_ARG_2_SI_IMM: mtype = v4si_ftype_v4si_si; break; + case MULTI_ARG_2_HI_IMM: mtype = v8hi_ftype_v8hi_si; break; + case MULTI_ARG_2_QI_IMM: mtype = v16qi_ftype_v16qi_si; break; + case MULTI_ARG_2_DI_CMP: mtype = v2di_ftype_v2di_v2di; break; + case MULTI_ARG_2_SI_CMP: mtype = v4si_ftype_v4si_v4si; break; + case MULTI_ARG_2_HI_CMP: mtype = v8hi_ftype_v8hi_v8hi; break; + case MULTI_ARG_2_QI_CMP: mtype = v16qi_ftype_v16qi_v16qi; break; + case MULTI_ARG_2_SF_TF: mtype = v4sf_ftype_v4sf_v4sf; break; + case MULTI_ARG_2_DF_TF: mtype = v2df_ftype_v2df_v2df; break; + case MULTI_ARG_2_DI_TF: mtype = v2di_ftype_v2di_v2di; break; + case MULTI_ARG_2_SI_TF: mtype = v4si_ftype_v4si_v4si; break; + case MULTI_ARG_2_HI_TF: mtype = v8hi_ftype_v8hi_v8hi; break; + case MULTI_ARG_2_QI_TF: mtype = v16qi_ftype_v16qi_v16qi; break; + case MULTI_ARG_1_SF: mtype = v4sf_ftype_v4sf; break; + case MULTI_ARG_1_DF: mtype = v2df_ftype_v2df; break; + case MULTI_ARG_1_SF2: mtype = v8sf_ftype_v8sf; break; + case MULTI_ARG_1_DF2: mtype = v4df_ftype_v4df; break; + case MULTI_ARG_1_DI: mtype = v2di_ftype_v2di; break; + case MULTI_ARG_1_SI: mtype = v4si_ftype_v4si; break; + case MULTI_ARG_1_HI: mtype = v8hi_ftype_v8hi; break; + case MULTI_ARG_1_QI: mtype = v16qi_ftype_v16qi; break; + case MULTI_ARG_1_SI_DI: mtype = v2di_ftype_v4si; break; + case MULTI_ARG_1_HI_DI: mtype = v2di_ftype_v8hi; break; + case MULTI_ARG_1_HI_SI: mtype = v4si_ftype_v8hi; break; + case MULTI_ARG_1_QI_DI: mtype = v2di_ftype_v16qi; break; + case MULTI_ARG_1_QI_SI: mtype = v4si_ftype_v16qi; break; + case MULTI_ARG_1_QI_HI: mtype = v8hi_ftype_v16qi; break; case MULTI_ARG_UNKNOWN: default: @@ -23440,6 +24221,17 @@ ix86_init_builtins (void) ix86_init_builtins_va_builtins_abi (); } +/* Return the ix86 builtin for CODE. */ + +static tree +ix86_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= IX86_BUILTIN_MAX) + return error_mark_node; + + return ix86_builtins[code]; +} + /* Errors in the source file can cause expand_expr to return const0_rtx where we expect a vector. To avoid crashing, use one of the vector clear instructions. */ @@ -23523,9 +24315,71 @@ ix86_expand_multi_arg_builtin (enum insn_code icode, tree exp, rtx target, case MULTI_ARG_3_DF: case MULTI_ARG_3_SF2: case MULTI_ARG_3_DF2: + case MULTI_ARG_3_DI: + case MULTI_ARG_3_SI: + case MULTI_ARG_3_SI_DI: + case MULTI_ARG_3_HI: + case MULTI_ARG_3_HI_SI: + case MULTI_ARG_3_QI: + case MULTI_ARG_3_DI2: + case MULTI_ARG_3_SI2: + case MULTI_ARG_3_HI2: + case MULTI_ARG_3_QI2: nargs = 3; break; + case MULTI_ARG_2_SF: + case MULTI_ARG_2_DF: + case MULTI_ARG_2_DI: + case MULTI_ARG_2_SI: + case MULTI_ARG_2_HI: + case MULTI_ARG_2_QI: + nargs = 2; + break; + + case MULTI_ARG_2_DI_IMM: + case MULTI_ARG_2_SI_IMM: + case MULTI_ARG_2_HI_IMM: + case MULTI_ARG_2_QI_IMM: + nargs = 2; + last_arg_constant = true; + break; + + case MULTI_ARG_1_SF: + case MULTI_ARG_1_DF: + case MULTI_ARG_1_SF2: + case MULTI_ARG_1_DF2: + case MULTI_ARG_1_DI: + case MULTI_ARG_1_SI: + case MULTI_ARG_1_HI: + case MULTI_ARG_1_QI: + case MULTI_ARG_1_SI_DI: + case MULTI_ARG_1_HI_DI: + case MULTI_ARG_1_HI_SI: + case MULTI_ARG_1_QI_DI: + case MULTI_ARG_1_QI_SI: + case MULTI_ARG_1_QI_HI: + nargs = 1; + break; + + case MULTI_ARG_2_DI_CMP: + case MULTI_ARG_2_SI_CMP: + case MULTI_ARG_2_HI_CMP: + case MULTI_ARG_2_QI_CMP: + nargs = 2; + comparison_p = true; + break; + + case MULTI_ARG_2_SF_TF: + case MULTI_ARG_2_DF_TF: + case MULTI_ARG_2_DI_TF: + case MULTI_ARG_2_SI_TF: + case MULTI_ARG_2_HI_TF: + case MULTI_ARG_2_QI_TF: + nargs = 2; + tf_p = true; + break; + case MULTI_ARG_UNKNOWN: default: gcc_unreachable (); @@ -24463,6 +25317,16 @@ ix86_expand_special_args_builtin (const struct builtin_description *d, /* Reserve memory operand for target. */ memory = ARRAY_SIZE (args); break; + case VOID_FTYPE_USHORT_UINT_USHORT: + case VOID_FTYPE_UINT_UINT_UINT: + case VOID_FTYPE_UINT64_UINT_UINT: + case UCHAR_FTYPE_USHORT_UINT_USHORT: + case UCHAR_FTYPE_UINT_UINT_UINT: + case UCHAR_FTYPE_UINT64_UINT_UINT: + nargs = 3; + klass = store; + memory = 0; + break; default: gcc_unreachable (); } @@ -25206,7 +26070,7 @@ static tree ix86_builtin_reciprocal (unsigned int fn, bool md_fn, bool sqrt ATTRIBUTE_UNUSED) { - if (! (TARGET_SSE_MATH && TARGET_RECIP && !optimize_insn_for_size_p () + if (! (TARGET_SSE_MATH && !optimize_insn_for_size_p () && flag_finite_math_only && !flag_trapping_math && flag_unsafe_math_optimizations)) return NULL_TREE; @@ -26455,6 +27319,33 @@ ix86_handle_struct_attribute (tree *node, tree name, return NULL_TREE; } +static tree +ix86_handle_fndecl_attribute (tree *node, tree name, + tree args ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED, bool *no_add_attrs) +{ + if (TREE_CODE (*node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + *no_add_attrs = true; + return NULL_TREE; + } + + if (TARGET_64BIT) + { + warning (OPT_Wattributes, "%qE attribute only available for 32-bit", + name); + return NULL_TREE; + } + +#ifndef HAVE_AS_IX86_SWAP + sorry ("ms_hook_prologue attribute needs assembler swap suffix support"); +#endif + + return NULL_TREE; +} + static bool ix86_ms_bitfield_layout_p (const_tree record_type) { @@ -28520,18 +29411,18 @@ void ix86_emit_swdivsf (rtx res, rtx a, rtx b, enum machine_mode mode) emit_insn (gen_rtx_SET (VOIDmode, x0, gen_rtx_UNSPEC (mode, gen_rtvec (1, b), UNSPEC_RCP))); - /* e0 = x0 * b */ + /* e0 = x0 * a */ emit_insn (gen_rtx_SET (VOIDmode, e0, - gen_rtx_MULT (mode, x0, b))); - /* e1 = 2. - e0 */ + gen_rtx_MULT (mode, x0, a))); + /* e1 = x0 * b */ emit_insn (gen_rtx_SET (VOIDmode, e1, - gen_rtx_MINUS (mode, two, e0))); - /* x1 = x0 * e1 */ + gen_rtx_MULT (mode, x0, b))); + /* x1 = 2. - e1 */ emit_insn (gen_rtx_SET (VOIDmode, x1, - gen_rtx_MULT (mode, x0, e1))); - /* res = a * x1 */ + gen_rtx_MINUS (mode, two, e1))); + /* res = e0 * x1 */ emit_insn (gen_rtx_SET (VOIDmode, res, - gen_rtx_MULT (mode, a, x1))); + gen_rtx_MULT (mode, e0, x1))); } /* Output code to perform a Newton-Rhapson approximation of a @@ -29497,6 +30388,7 @@ static const struct attribute_spec ix86_attribute_table[] = /* ms_abi and sysv_abi calling convention function attributes. */ { "ms_abi", 0, 0, false, true, true, ix86_handle_abi_attribute }, { "sysv_abi", 0, 0, false, true, true, ix86_handle_abi_attribute }, + { "ms_hook_prologue", 0, 0, true, false, false, ix86_handle_fndecl_attribute }, /* End element. */ { NULL, 0, 0, false, false, false, NULL } }; @@ -29663,6 +30555,8 @@ ix86_enum_va_list (int idx, const char **pname, tree *ptree) #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS ix86_init_builtins +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL ix86_builtin_decl #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN ix86_expand_builtin diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index 8d525727eec..4bc8ef18500 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -55,6 +55,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define TARGET_FMA OPTION_ISA_FMA #define TARGET_SSE4A OPTION_ISA_SSE4A #define TARGET_FMA4 OPTION_ISA_FMA4 +#define TARGET_XOP OPTION_ISA_XOP +#define TARGET_LWP OPTION_ISA_LWP #define TARGET_ROUND OPTION_ISA_ROUND #define TARGET_ABM OPTION_ISA_ABM #define TARGET_POPCNT OPTION_ISA_POPCNT @@ -400,6 +402,7 @@ enum ix86_arch_indices { X86_ARCH_CMPXCHG8B, X86_ARCH_XADD, X86_ARCH_BSWAP, + X86_ARCH_CALL_ESP, X86_ARCH_LAST }; @@ -411,6 +414,7 @@ extern unsigned char ix86_arch_features[X86_ARCH_LAST]; #define TARGET_CMPXCHG8B ix86_arch_features[X86_ARCH_CMPXCHG8B] #define TARGET_XADD ix86_arch_features[X86_ARCH_XADD] #define TARGET_BSWAP ix86_arch_features[X86_ARCH_BSWAP] +#define TARGET_CALL_ESP ix86_arch_features[X86_ARCH_CALL_ESP] #define TARGET_FISTTP (TARGET_SSE3 && TARGET_80387) @@ -706,9 +710,7 @@ enum target_cpu_default generate an alternate prologue and epilogue that realigns the runtime stack if nessary. This supports mixing codes that keep a 4-byte aligned stack, as specified by i386 psABI, with codes that - need a 16-byte aligned stack, as required by SSE instructions. If - STACK_REALIGN_DEFAULT is 1 and PREFERRED_STACK_BOUNDARY_DEFAULT is - 128, stacks for all functions may be realigned. */ + need a 16-byte aligned stack, as required by SSE instructions. */ #define STACK_REALIGN_DEFAULT 0 /* Boundary (in *bits*) on which the incoming stack is aligned. */ @@ -873,6 +875,9 @@ enum target_cpu_default || ((MODE) == DFmode && (!TARGET_SSE2 || !TARGET_SSE_MATH)) \ || (MODE) == XFmode) +/* Cover class containing the stack registers. */ +#define STACK_REG_COVER_CLASS FLOAT_REGS + /* Number of actual hardware registers. The hardware registers are assigned numbers for the compiler from 0 to just below FIRST_PSEUDO_REGISTER. diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 27800804eca..82f5352597c 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -57,6 +57,7 @@ ;; X -- don't print any sort of PIC '@' suffix for a symbol. ;; & -- print some in-use local-dynamic symbol name. ;; H -- print a memory address offset by 8; used for sse high-parts +;; Y -- print condition for XOP pcom* instruction. ;; + -- print a branch hint as 'cs' or 'ds' prefix ;; ; -- print a semicolon (after prefixes due to bug in older gas). @@ -199,6 +200,15 @@ (UNSPEC_FMA4_INTRINSIC 150) (UNSPEC_FMA4_FMADDSUB 151) (UNSPEC_FMA4_FMSUBADD 152) + (UNSPEC_XOP_UNSIGNED_CMP 151) + (UNSPEC_XOP_TRUEFALSE 152) + (UNSPEC_XOP_PERMUTE 153) + (UNSPEC_FRCZ 154) + (UNSPEC_LLWP_INTRINSIC 155) + (UNSPEC_SLWP_INTRINSIC 156) + (UNSPECV_LWPVAL_INTRINSIC 157) + (UNSPECV_LWPINS_INTRINSIC 158) + ; For AES support (UNSPEC_AESENC 159) (UNSPEC_AESENCLAST 160) @@ -241,6 +251,7 @@ (UNSPECV_RDTSC 18) (UNSPECV_RDTSCP 19) (UNSPECV_RDPMC 20) + (UNSPECV_VSWAPMOV 21) ]) ;; Constants to represent pcomtrue/pcomfalse variants @@ -253,6 +264,20 @@ (COM_TRUE_P 5) ]) +;; Constants used in the XOP pperm instruction +(define_constants + [(PPERM_SRC 0x00) /* copy source */ + (PPERM_INVERT 0x20) /* invert source */ + (PPERM_REVERSE 0x40) /* bit reverse source */ + (PPERM_REV_INV 0x60) /* bit reverse & invert src */ + (PPERM_ZERO 0x80) /* all 0's */ + (PPERM_ONES 0xa0) /* all 1's */ + (PPERM_SIGN 0xc0) /* propagate sign bit */ + (PPERM_INV_SIGN 0xe0) /* invert & propagate sign */ + (PPERM_SRC1 0x00) /* use first source byte */ + (PPERM_SRC2 0x10) /* use second source byte */ + ]) + ;; Registers by name. (define_constants [(AX_REG 0) @@ -332,7 +357,7 @@ fmov,fop,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,fistp,fisttp,frndint, sselog,sselog1,sseiadd,sseiadd1,sseishft,sseimul, sse,ssemov,sseadd,ssemul,ssecmp,ssecomi,ssecvt,ssecvt1,sseicvt,ssediv,sseins, - ssemuladd,sse4arg, + ssemuladd,sse4arg,lwp, mmx,mmxmov,mmxadd,mmxmul,mmxcmp,mmxcvt,mmxshft" (const_string "other")) @@ -702,12 +727,52 @@ ;; Base name for x87 insn mnemonic. (define_code_attr absnegprefix [(abs "abs") (neg "chs")]) +;; Used in signed and unsigned widening multiplications. +(define_code_iterator any_extend [sign_extend zero_extend]) + +;; Used in signed and unsigned divisions. +(define_code_iterator any_div [div udiv]) + +;; Various insn prefixes for signed and unsigned operations. +(define_code_attr u [(sign_extend "") (zero_extend "u") + (div "") (udiv "u")]) +(define_code_attr s [(sign_extend "s") (zero_extend "u")]) + +;; Instruction prefix for signed and unsigned operations. +(define_code_attr sgnprefix [(sign_extend "i") (zero_extend "") + (div "i") (udiv "")]) + ;; All single word integer modes. (define_mode_iterator SWI [QI HI SI (DI "TARGET_64BIT")]) ;; Single word integer modes without QImode. (define_mode_iterator SWI248 [HI SI (DI "TARGET_64BIT")]) +;; Single word integer modes without QImode and HImode. +(define_mode_iterator SWI48 [SI (DI "TARGET_64BIT")]) + +;; All math-dependant single and double word integer modes. +(define_mode_iterator SDWIM [(QI "TARGET_QIMODE_MATH") + (HI "TARGET_HIMODE_MATH") + SI DI (TI "TARGET_64BIT")]) + +;; Math-dependant single word integer modes. +(define_mode_iterator SWIM [(QI "TARGET_QIMODE_MATH") + (HI "TARGET_HIMODE_MATH") + SI (DI "TARGET_64BIT")]) + +;; Math-dependant single word integer modes without QImode. +(define_mode_iterator SWIM248 [(HI "TARGET_HIMODE_MATH") + SI (DI "TARGET_64BIT")]) + +;; Half mode for double word integer modes. +(define_mode_iterator DWIH [(SI "!TARGET_64BIT") + (DI "TARGET_64BIT")]) + +;; Double word integer modes. +(define_mode_attr DWI [(SI "DI") (DI "TI")]) +(define_mode_attr dwi [(SI "di") (DI "ti")]) + ;; Instruction suffix for integer modes. (define_mode_attr imodesuffix [(QI "b") (HI "w") (SI "l") (DI "q")]) @@ -717,12 +782,19 @@ ;; Immediate operand constraint for integer modes. (define_mode_attr i [(QI "n") (HI "n") (SI "i") (DI "e")]) +;; General operand constraint for word modes. +(define_mode_attr g [(SI "g") (DI "rme")]) + +;; Immediate operand constraint for double integer modes. +(define_mode_attr di [(SI "iF") (DI "e")]) + ;; General operand predicate for integer modes. (define_mode_attr general_operand [(QI "general_operand") (HI "general_operand") (SI "general_operand") - (DI "x86_64_general_operand")]) + (DI "x86_64_general_operand") + (TI "x86_64_general_operand")]) ;; SSE and x87 SFmode and DFmode floating point modes (define_mode_iterator MODEF [SF DF]) @@ -752,7 +824,6 @@ ;; This mode iterator allows :P to be used for patterns that operate on ;; pointer-sized quantities. Exactly one of the two alternatives will match. (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) - ;; Scheduling descriptions @@ -2994,7 +3065,6 @@ [(set (match_dup 0) (match_dup 2))]) - ;; %%% Kill this when call knows how to work this out. (define_split [(set (match_operand:SF 0 "push_operand" "") @@ -4040,9 +4110,11 @@ && (TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)) && !reg_overlap_mentioned_p (operands[0], operands[1])" - [(set (match_dup 0) (const_int 0)) - (set (strict_low_part (match_dup 2)) (match_dup 1))] - "operands[2] = gen_lowpart (QImode, operands[0]);") + [(set (strict_low_part (match_dup 2)) (match_dup 1))] +{ + operands[2] = gen_lowpart (QImode, operands[0]); + ix86_expand_clear (operands[0]); +}) ;; Rest is handled by single and. (define_split @@ -4072,7 +4144,7 @@ [(set_attr "type" "alu1") (set_attr "mode" "SI")]) -(define_insn "*zero_extendqisi2_movzbw_and" +(define_insn "*zero_extendqisi2_movzbl_and" [(set (match_operand:SI 0 "register_operand" "=r,r") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm,0"))) (clobber (reg:CC FLAGS_REG))] @@ -4081,7 +4153,7 @@ [(set_attr "type" "imovx,alu1") (set_attr "mode" "SI")]) -(define_insn "*zero_extendqisi2_movzbw" +(define_insn "*zero_extendqisi2_movzbl" [(set (match_operand:SI 0 "register_operand" "=r") (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))] "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_function_for_size_p (cfun)) @@ -4112,9 +4184,11 @@ && (ANY_QI_REG_P (operands[1]) || MEM_P (operands[1])) && (TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)) && !reg_overlap_mentioned_p (operands[0], operands[1])" - [(set (match_dup 0) (const_int 0)) - (set (strict_low_part (match_dup 2)) (match_dup 1))] - "operands[2] = gen_lowpart (QImode, operands[0]);") + [(set (strict_low_part (match_dup 2)) (match_dup 1))] +{ + operands[2] = gen_lowpart (QImode, operands[0]); + ix86_expand_clear (operands[0]); +}) ;; Rest is handled by single and. (define_split @@ -5426,11 +5500,18 @@ && !X87_ENABLE_FLOAT (mode, mode)) { rtx reg = gen_reg_rtx (XFmode); + rtx insn; + emit_insn (gen_floatxf2 (reg, operands[1])); -/* Avoid references to nonexistent function in dead code in XFmode case. */ -#define gen_truncxfxf2 gen_truncxfdf2 - emit_insn (gen_truncxf2 (operands[0], reg)); -#undef gen_truncxfxf2 + + if (mode == SFmode) + insn = gen_truncxfsf2 (operands[0], reg); + else if (mode == DFmode) + insn = gen_truncxfdf2 (operands[0], reg); + else + gcc_unreachable (); + + emit_insn (insn); DONE; } }") @@ -6046,195 +6127,57 @@ ;; Add instructions -;; %%% splits for addditi3 - -(define_expand "addti3" - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (plus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "x86_64_general_operand" "")))] - "TARGET_64BIT" - "ix86_expand_binary_operator (PLUS, TImode, operands); DONE;") - -(define_insn "*addti3_1" - [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o") - (plus:TI (match_operand:TI 1 "nonimmediate_operand" "%0,0") - (match_operand:TI 2 "x86_64_general_operand" "roe,re"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (PLUS, TImode, operands)" - "#") - -(define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (plus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "x86_64_general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (unspec:CC [(match_dup 1) (match_dup 2)] - UNSPEC_ADD_CARRY)) - (set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))]) - (parallel [(set (match_dup 3) - (plus:DI (plus:DI (ltu:DI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 4)) - (match_dup 5))) - (clobber (reg:CC FLAGS_REG))])] - "split_ti (&operands[0], 3, &operands[0], &operands[3]);") - -;; %%% splits for addsidi3 -; [(set (match_operand:DI 0 "nonimmediate_operand" "") -; (plus:DI (match_operand:DI 1 "general_operand" "") -; (zero_extend:DI (match_operand:SI 2 "general_operand" ""))))] - -(define_expand "adddi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "x86_64_general_operand" "")))] +(define_expand "add3" + [(set (match_operand:SDWIM 0 "nonimmediate_operand" "") + (plus:SDWIM (match_operand:SDWIM 1 "nonimmediate_operand" "") + (match_operand:SDWIM 2 "" "")))] "" - "ix86_expand_binary_operator (PLUS, DImode, operands); DONE;") - -(define_insn "*adddi3_1" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "general_operand" "roiF,riF"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" - "#") + "ix86_expand_binary_operator (PLUS, mode, operands); DONE;") -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "general_operand" ""))) +(define_insn_and_split "*add3_doubleword" + [(set (match_operand: 0 "nonimmediate_operand" "=r,o") + (plus: + (match_operand: 1 "nonimmediate_operand" "%0,0") + (match_operand: 2 "" "ro,r"))) (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (unspec:CC [(match_dup 1) (match_dup 2)] - UNSPEC_ADD_CARRY)) - (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))]) + "ix86_binary_operator_ok (PLUS, mode, operands)" + "#" + "reload_completed" + [(parallel [(set (reg:CC FLAGS_REG) + (unspec:CC [(match_dup 1) (match_dup 2)] + UNSPEC_ADD_CARRY)) + (set (match_dup 0) + (plus:DWIH (match_dup 1) (match_dup 2)))]) (parallel [(set (match_dup 3) - (plus:SI (plus:SI (ltu:SI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 4)) - (match_dup 5))) + (plus:DWIH + (plus:DWIH + (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)) + (match_dup 4)) + (match_dup 5))) (clobber (reg:CC FLAGS_REG))])] - "split_di (&operands[0], 3, &operands[0], &operands[3]);") + "split_ (&operands[0], 3, &operands[0], &operands[3]);") -(define_insn "adddi3_carry_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (plus:DI (plus:DI (match_operand:DI 3 "ix86_carry_flag_operator" "") - (match_operand:DI 1 "nonimmediate_operand" "%0,0")) - (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) +(define_insn "add3_carry" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (plus:SWI + (plus:SWI (match_operand:SWI 3 "ix86_carry_flag_operator" "") + (match_operand:SWI 1 "nonimmediate_operand" "%0,0")) + (match_operand:SWI 2 "" ",m"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" - "adc{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "DI")]) - -(define_insn "*adddi3_cc_rex64" - [(set (reg:CC FLAGS_REG) - (unspec:CC [(match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "x86_64_general_operand" "re,rm")] - UNSPEC_ADD_CARRY)) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (plus:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" - "add{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - -(define_insn "*3_cc_overflow" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (plusminus:SWI - (match_operand:SWI 1 "nonimmediate_operand" "0,0") - (match_operand:SWI 2 "" ",m")) - (match_dup 1))) - (set (match_operand:SWI 0 "nonimmediate_operand" "=m,") - (plusminus:SWI (match_dup 1) (match_dup 2)))] - "ix86_binary_operator_ok (, mode, operands)" - "{}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "")]) - -(define_insn "*add3_cconly_overflow" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (plus:SWI (match_operand:SWI 1 "nonimmediate_operand" "%0") - (match_operand:SWI 2 "" "m")) - (match_dup 1))) - (clobber (match_scratch:SWI 0 "="))] "ix86_binary_operator_ok (PLUS, mode, operands)" - "add{}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "")]) - -(define_insn "*sub3_cconly_overflow" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (minus:SWI (match_operand:SWI 0 "nonimmediate_operand" "m,") - (match_operand:SWI 1 "" ",m")) - (match_dup 0)))] - "" - "cmp{}\t{%1, %0|%0, %1}" - [(set_attr "type" "icmp") - (set_attr "mode" "")]) - -(define_insn "*si3_zext_cc_overflow" - [(set (reg:CCC FLAGS_REG) - (compare:CCC - (plusminus:SI (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:SI 2 "general_operand" "g")) - (match_dup 1))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (plusminus:SI (match_dup 1) (match_dup 2))))] - "TARGET_64BIT && ix86_binary_operator_ok (, SImode, operands)" - "{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) - -(define_insn "addqi3_carry" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") - (plus:QI (plus:QI (match_operand:QI 3 "ix86_carry_flag_operator" "") - (match_operand:QI 1 "nonimmediate_operand" "%0,0")) - (match_operand:QI 2 "general_operand" "qn,qm"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (PLUS, QImode, operands)" - "adc{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "QI")]) - -(define_insn "addhi3_carry" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (plus:HI (plus:HI (match_operand:HI 3 "ix86_carry_flag_operator" "") - (match_operand:HI 1 "nonimmediate_operand" "%0,0")) - (match_operand:HI 2 "general_operand" "rn,rm"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (PLUS, HImode, operands)" - "adc{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "HI")]) - -(define_insn "addsi3_carry" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (plus:SI (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") - (match_operand:SI 1 "nonimmediate_operand" "%0,0")) - (match_operand:SI 2 "general_operand" "ri,rm"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (PLUS, SImode, operands)" - "adc{l}\t{%2, %0|%0, %2}" + "adc{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "use_carry" "1") (set_attr "pent_pair" "pu") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) (define_insn "*addsi3_carry_zext" [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (plus:SI (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") - (match_operand:SI 1 "nonimmediate_operand" "%0")) - (match_operand:SI 2 "general_operand" "g")))) + (zero_extend:DI + (plus:SI + (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") + (match_operand:SI 1 "nonimmediate_operand" "%0")) + (match_operand:SI 2 "general_operand" "g")))) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" "adc{l}\t{%2, %k0|%k0, %2}" @@ -6243,23 +6186,25 @@ (set_attr "pent_pair" "pu") (set_attr "mode" "SI")]) -(define_insn "*addsi3_cc" +(define_insn "*add3_cc" [(set (reg:CC FLAGS_REG) - (unspec:CC [(match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "ri,rm")] - UNSPEC_ADD_CARRY)) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (plus:SI (match_dup 1) (match_dup 2)))] - "ix86_binary_operator_ok (PLUS, SImode, operands)" - "add{l}\t{%2, %0|%0, %2}" + (unspec:CC + [(match_operand:SWI48 1 "nonimmediate_operand" "%0,0") + (match_operand:SWI48 2 "" "r,rm")] + UNSPEC_ADD_CARRY)) + (set (match_operand:SWI48 0 "nonimmediate_operand" "=rm,r") + (plus:SWI48 (match_dup 1) (match_dup 2)))] + "ix86_binary_operator_ok (PLUS, mode, operands)" + "add{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) (define_insn "addqi3_cc" [(set (reg:CC FLAGS_REG) - (unspec:CC [(match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "qn,qm")] - UNSPEC_ADD_CARRY)) + (unspec:CC + [(match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qn,qm")] + UNSPEC_ADD_CARRY)) (set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") (plus:QI (match_dup 1) (match_dup 2)))] "ix86_binary_operator_ok (PLUS, QImode, operands)" @@ -6267,22 +6212,28 @@ [(set_attr "type" "alu") (set_attr "mode" "QI")]) -(define_expand "addsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" "")))] - "" - "ix86_expand_binary_operator (PLUS, SImode, operands); DONE;") +(define_insn "*add3_cconly_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (plus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "%0") + (match_operand:SWI 2 "" "m")) + (match_dup 1))) + (clobber (match_scratch:SWI 0 "="))] + "ix86_binary_operator_ok (PLUS, mode, operands)" + "add{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "")]) (define_insn "*lea_1" - [(set (match_operand:SI 0 "register_operand" "=r") - (match_operand:SI 1 "no_seg_address_operand" "p"))] - "!TARGET_64BIT" - "lea{l}\t{%a1, %0|%0, %a1}" + [(set (match_operand:DWIH 0 "register_operand" "=r") + (match_operand:DWIH 1 "no_seg_address_operand" "p"))] + "" + "lea{}\t{%a1, %0|%0, %a1}" [(set_attr "type" "lea") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) -(define_insn "*lea_1_rex64" +(define_insn "*lea_2" [(set (match_operand:SI 0 "register_operand" "=r") (subreg:SI (match_operand:DI 1 "no_seg_address_operand" "p") 0))] "TARGET_64BIT" @@ -6290,240 +6241,134 @@ [(set_attr "type" "lea") (set_attr "mode" "SI")]) -(define_insn "*lea_1_zext" +(define_insn "*lea_2_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI - (subreg:SI (match_operand:DI 1 "no_seg_address_operand" "p") 0)))] + (subreg:SI (match_operand:DI 1 "no_seg_address_operand" "p") 0)))] "TARGET_64BIT" "lea{l}\t{%a1, %k0|%k0, %a1}" [(set_attr "type" "lea") (set_attr "mode" "SI")]) -(define_insn "*lea_2_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (match_operand:DI 1 "no_seg_address_operand" "p"))] - "TARGET_64BIT" - "lea{q}\t{%a1, %0|%0, %a1}" - [(set_attr "type" "lea") - (set_attr "mode" "DI")]) +(define_insn "*add_1" + [(set (match_operand:SWI48 0 "nonimmediate_operand" "=r,rm,r,r") + (plus:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "%0,0,r,r") + (match_operand:SWI48 2 "" ",r,0,l"))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (PLUS, mode, operands)" +{ + switch (get_attr_type (insn)) + { + case TYPE_LEA: + operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); + return "lea{}\t{%a2, %0|%0, %a2}"; -;; The lea patterns for non-Pmodes needs to be matched by several -;; insns converted to real lea by splitters. + case TYPE_INCDEC: + gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (operands[2] == const1_rtx) + return "inc{}\t%0"; + else + { + gcc_assert (operands[2] == constm1_rtx); + return "dec{}\t%0"; + } -(define_insn_and_split "*lea_general_1" - [(set (match_operand 0 "register_operand" "=r") - (plus (plus (match_operand 1 "index_register_operand" "l") - (match_operand 2 "register_operand" "r")) - (match_operand 3 "immediate_operand" "i")))] - "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode - || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) - && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && GET_MODE (operands[0]) == GET_MODE (operands[1]) - && GET_MODE (operands[0]) == GET_MODE (operands[2]) - && (GET_MODE (operands[0]) == GET_MODE (operands[3]) - || GET_MODE (operands[3]) == VOIDmode)" - "#" - "&& reload_completed" - [(const_int 0)] -{ - rtx pat; - operands[0] = gen_lowpart (SImode, operands[0]); - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[2] = gen_lowpart (Pmode, operands[2]); - operands[3] = gen_lowpart (Pmode, operands[3]); - pat = gen_rtx_PLUS (Pmode, gen_rtx_PLUS (Pmode, operands[1], operands[2]), - operands[3]); - if (Pmode != SImode) - pat = gen_rtx_SUBREG (SImode, pat, 0); - emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); - DONE; + default: + /* Use add as much as possible to replace lea for AGU optimization. */ + if (which_alternative == 2 && TARGET_OPT_AGU) + return "add{}\t{%1, %0|%0, %1}"; + + gcc_assert (rtx_equal_p (operands[0], operands[1])); + + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (CONST_INT_P (operands[2]) + /* Avoid overflows. */ + && (mode != DImode + || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{}\t{%2, %0|%0, %2}"; + } + return "add{}\t{%2, %0|%0, %2}"; + } } - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) + [(set (attr "type") + (cond [(and (eq_attr "alternative" "2") + (eq (symbol_ref "TARGET_OPT_AGU") (const_int 0))) + (const_string "lea") + (eq_attr "alternative" "3") + (const_string "lea") + ; Current assemblers are broken and do not allow @GOTOFF in + ; ought but a memory context. + (match_operand:SWI48 2 "pic_symbolic_operand" "") + (const_string "lea") + (match_operand:SWI48 2 "incdec_operand" "") + (const_string "incdec") + ] + (const_string "alu"))) + (set (attr "length_immediate") + (if_then_else + (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) + (const_string "1") + (const_string "*"))) + (set_attr "mode" "")]) -(define_insn_and_split "*lea_general_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r") +;; It may seem that nonimmediate operand is proper one for operand 1. +;; The addsi_1 pattern allows nonimmediate operand at that place and +;; we take care in ix86_binary_operator_ok to not allow two memory +;; operands so proper swapping will be done in reload. This allow +;; patterns constructed from addsi_1 to match. + +(define_insn "*addsi_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r,r") (zero_extend:DI - (plus:SI (plus:SI (match_operand:SI 1 "index_register_operand" "l") - (match_operand:SI 2 "register_operand" "r")) - (match_operand:SI 3 "immediate_operand" "i"))))] - "TARGET_64BIT" - "#" - "&& reload_completed" - [(set (match_dup 0) - (zero_extend:DI (subreg:SI (plus:DI (plus:DI (match_dup 1) - (match_dup 2)) - (match_dup 3)) 0)))] + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,r") + (match_operand:SI 2 "general_operand" "g,li")))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" { - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[2] = gen_lowpart (Pmode, operands[2]); - operands[3] = gen_lowpart (Pmode, operands[3]); -} - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn_and_split "*lea_general_2" - [(set (match_operand 0 "register_operand" "=r") - (plus (mult (match_operand 1 "index_register_operand" "l") - (match_operand 2 "const248_operand" "i")) - (match_operand 3 "nonmemory_operand" "ri")))] - "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode - || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) - && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && GET_MODE (operands[0]) == GET_MODE (operands[1]) - && (GET_MODE (operands[0]) == GET_MODE (operands[3]) - || GET_MODE (operands[3]) == VOIDmode)" - "#" - "&& reload_completed" - [(const_int 0)] -{ - rtx pat; - operands[0] = gen_lowpart (SImode, operands[0]); - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[3] = gen_lowpart (Pmode, operands[3]); - pat = gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], operands[2]), - operands[3]); - if (Pmode != SImode) - pat = gen_rtx_SUBREG (SImode, pat, 0); - emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); - DONE; -} - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn_and_split "*lea_general_2_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (plus:SI (mult:SI (match_operand:SI 1 "index_register_operand" "l") - (match_operand:SI 2 "const248_operand" "n")) - (match_operand:SI 3 "nonmemory_operand" "ri"))))] - "TARGET_64BIT" - "#" - "&& reload_completed" - [(set (match_dup 0) - (zero_extend:DI (subreg:SI (plus:DI (mult:DI (match_dup 1) - (match_dup 2)) - (match_dup 3)) 0)))] -{ - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[3] = gen_lowpart (Pmode, operands[3]); -} - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn_and_split "*lea_general_3" - [(set (match_operand 0 "register_operand" "=r") - (plus (plus (mult (match_operand 1 "index_register_operand" "l") - (match_operand 2 "const248_operand" "i")) - (match_operand 3 "register_operand" "r")) - (match_operand 4 "immediate_operand" "i")))] - "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode - || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) - && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && GET_MODE (operands[0]) == GET_MODE (operands[1]) - && GET_MODE (operands[0]) == GET_MODE (operands[3])" - "#" - "&& reload_completed" - [(const_int 0)] -{ - rtx pat; - operands[0] = gen_lowpart (SImode, operands[0]); - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[3] = gen_lowpart (Pmode, operands[3]); - operands[4] = gen_lowpart (Pmode, operands[4]); - pat = gen_rtx_PLUS (Pmode, - gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], - operands[2]), - operands[3]), - operands[4]); - if (Pmode != SImode) - pat = gen_rtx_SUBREG (SImode, pat, 0); - emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); - DONE; -} - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn_and_split "*lea_general_3_zext" - [(set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (plus:SI (plus:SI (mult:SI - (match_operand:SI 1 "index_register_operand" "l") - (match_operand:SI 2 "const248_operand" "n")) - (match_operand:SI 3 "register_operand" "r")) - (match_operand:SI 4 "immediate_operand" "i"))))] - "TARGET_64BIT" - "#" - "&& reload_completed" - [(set (match_dup 0) - (zero_extend:DI (subreg:SI (plus:DI (plus:DI (mult:DI (match_dup 1) - (match_dup 2)) - (match_dup 3)) - (match_dup 4)) 0)))] -{ - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[3] = gen_lowpart (Pmode, operands[3]); - operands[4] = gen_lowpart (Pmode, operands[4]); -} - [(set_attr "type" "lea") - (set_attr "mode" "SI")]) - -(define_insn "*adddi_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,rm,r,r") - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0,r,r") - (match_operand:DI 2 "x86_64_general_operand" "rme,re,0,le"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (PLUS, DImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_LEA: - operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - return "lea{q}\t{%a2, %0|%0, %a2}"; + switch (get_attr_type (insn)) + { + case TYPE_LEA: + operands[2] = XEXP (SET_SRC (XVECEXP (PATTERN (insn), 0, 0)), 0); + return "lea{l}\t{%a2, %k0|%k0, %a2}"; case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{q}\t%0"; + return "inc{l}\t%k0"; else { gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; + return "dec{l}\t%k0"; } default: - /* Use add as much as possible to replace lea for AGU optimization. */ - if (which_alternative == 2 && TARGET_OPT_AGU) - return "add{q}\t{%1, %0|%0, %1}"; - - gcc_assert (rtx_equal_p (operands[0], operands[1])); - - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) { operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{q}\t{%2, %0|%0, %2}"; + return "sub{l}\t{%2, %k0|%k0, %2}"; } - return "add{q}\t{%2, %0|%0, %2}"; + return "add{l}\t{%2, %k0|%k0, %2}"; } } [(set (attr "type") - (cond [(and (eq_attr "alternative" "2") - (eq (symbol_ref "TARGET_OPT_AGU") (const_int 0))) + (cond [(eq_attr "alternative" "1") (const_string "lea") - (eq_attr "alternative" "3") - (const_string "lea") ; Current assemblers are broken and do not allow @GOTOFF in ; ought but a memory context. - (match_operand:DI 2 "pic_symbolic_operand" "") + (match_operand:SI 2 "pic_symbolic_operand" "") (const_string "lea") - (match_operand:DI 2 "incdec_operand" "") + (match_operand:SI 2 "incdec_operand" "") (const_string "incdec") ] (const_string "alu"))) @@ -6532,68 +6377,43 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "DI")]) + (set_attr "mode" "SI")]) -;; Convert lea to the lea pattern to avoid flags dependency. -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (plus:DI (match_operand:DI 1 "register_operand" "") - (match_operand:DI 2 "x86_64_nonmemory_operand" ""))) +(define_insn "*addhi_1" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rn,rm"))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed - && ix86_lea_for_add_ok (PLUS, insn, operands)" - [(set (match_dup 0) - (plus:DI (match_dup 1) - (match_dup 2)))] - "") - -(define_insn "*adddi_2_rex64" - [(set (reg FLAGS_REG) - (compare - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0") - (match_operand:DI 2 "x86_64_general_operand" "rme,re")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=r,rm") - (plus:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, DImode, operands) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, HImode, operands)" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{q}\t%0"; + return "inc{w}\t%0"; else { gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; + return "dec{w}\t%0"; } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* ???? We ought to handle there the 32bit case too - - do we need new constraint? */ - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{q}\t{%2, %0|%0, %2}"; - } - return "add{q}\t{%2, %0|%0, %2}"; + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; + } + return "add{w}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:DI 2 "incdec_operand" "") + (if_then_else (match_operand:HI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -6601,105 +6421,102 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "DI")]) + (set_attr "mode" "HI")]) -(define_insn "*adddi_3_rex64" - [(set (reg FLAGS_REG) - (compare (neg:DI (match_operand:DI 2 "x86_64_general_operand" "rme")) - (match_operand:DI 1 "x86_64_general_operand" "%0"))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && ix86_match_ccmode (insn, CCZmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2])) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" +;; %%% After Dave's SUBREG_BYTE stuff goes in, re-enable incb %ah +;; type optimizations enabled by define-splits. This is not important +;; for PII, and in fact harmful because of partial register stalls. + +(define_insn "*addhi_1_lea" + [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r") + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r") + (match_operand:HI 2 "general_operand" "rn,rm,ln"))) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, HImode, operands)" { switch (get_attr_type (insn)) { + case TYPE_LEA: + return "#"; case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{q}\t%0"; + return "inc{w}\t%0"; else - { + { gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; + return "dec{w}\t%0"; } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* ???? We ought to handle there the 32bit case too - - do we need new constraint? */ - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{q}\t{%2, %0|%0, %2}"; - } - return "add{q}\t{%2, %0|%0, %2}"; + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; + } + return "add{w}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:DI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) + (if_then_else (eq_attr "alternative" "2") + (const_string "lea") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu")))) (set (attr "length_immediate") (if_then_else (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "DI")]) + (set_attr "mode" "HI,HI,SI")]) -; For comparisons against 1, -1 and 128, we may generate better code -; by converting cmp to add, inc or dec as done by peephole2. This pattern -; is matched then. We can't accept general immediate, because for -; case of overflows, the result is messed up. -; This pattern also don't hold of 0x8000000000000000, since the value overflows -; when negated. -; Also carry flag is reversed compared to cmp, so this conversion is valid -; only for comparisons not depending on it. -(define_insn "*adddi_4_rex64" - [(set (reg FLAGS_REG) - (compare (match_operand:DI 1 "nonimmediate_operand" "0") - (match_operand:DI 2 "x86_64_immediate_operand" "e"))) - (clobber (match_scratch:DI 0 "=rm"))] - "TARGET_64BIT - && ix86_match_ccmode (insn, CCGCmode)" +(define_insn "*addqi_1" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") + (match_operand:QI 2 "general_operand" "qn,qmn,rn"))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, QImode, operands)" { + int widen = (which_alternative == 2); switch (get_attr_type (insn)) { case TYPE_INCDEC: - if (operands[2] == constm1_rtx) - return "inc{q}\t%0"; + if (operands[2] == const1_rtx) + return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{q}\t%0"; + { + gcc_assert (operands[2] == constm1_rtx); + return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if ((INTVAL (operands[2]) == -128 - || (INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) != 128)) - /* Avoid overflows. */ - && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) - return "sub{q}\t{%2, %0|%0, %2}"; - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{q}\t{%2, %0|%0, %2}"; + if (CONST_INT_P (operands[2]) + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + if (widen) + return "sub{l}\t{%2, %k0|%k0, %2}"; + else + return "sub{b}\t{%2, %0|%0, %2}"; + } + if (widen) + return "add{l}\t{%k2, %k0|%k0, %k2}"; + else + return "add{b}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:DI 2 "incdec_operand" "") + (if_then_else (match_operand:QI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -6707,182 +6524,190 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "DI")]) + (set_attr "mode" "QI,QI,SI")]) -(define_insn "*adddi_5_rex64" - [(set (reg FLAGS_REG) - (compare - (plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0") - (match_operand:DI 2 "x86_64_general_operand" "rme")) - (const_int 0))) - (clobber (match_scratch:DI 0 "=r"))] - "TARGET_64BIT - && ix86_match_ccmode (insn, CCGOCmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2])) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" +;; %%% Potential partial reg stall on alternative 2. What to do? +(define_insn "*addqi_1_lea" + [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r,r") + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,r") + (match_operand:QI 2 "general_operand" "qn,qmn,rn,ln"))) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_PARTIAL_REG_STALL + && ix86_binary_operator_ok (PLUS, QImode, operands)" { + int widen = (which_alternative == 2); switch (get_attr_type (insn)) { + case TYPE_LEA: + return "#"; case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{q}\t%0"; + return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{q}\t%0"; + { + gcc_assert (operands[2] == constm1_rtx); + return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) - /* Avoid overflows. */ - && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1))) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{q}\t{%2, %0|%0, %2}"; - } - return "add{q}\t{%2, %0|%0, %2}"; + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + if (widen) + return "sub{l}\t{%2, %k0|%k0, %2}"; + else + return "sub{b}\t{%2, %0|%0, %2}"; + } + if (widen) + return "add{l}\t{%k2, %k0|%k0, %k2}"; + else + return "add{b}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:DI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) + (if_then_else (eq_attr "alternative" "3") + (const_string "lea") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu")))) (set (attr "length_immediate") (if_then_else (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "DI")]) - + (set_attr "mode" "QI,QI,SI,SI")]) -(define_insn "*addsi_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r,r") - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r,r") - (match_operand:SI 2 "general_operand" "g,ri,0,li"))) +(define_insn "*addqi_1_slp" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) + (plus:QI (match_dup 0) + (match_operand:QI 1 "general_operand" "qn,qnm"))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (PLUS, SImode, operands)" + "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + && !(MEM_P (operands[0]) && MEM_P (operands[1]))" { switch (get_attr_type (insn)) { - case TYPE_LEA: - operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - return "lea{l}\t{%a2, %0|%0, %a2}"; - case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - if (operands[2] == const1_rtx) - return "inc{l}\t%0"; + if (operands[1] == const1_rtx) + return "inc{b}\t%0"; else { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%0"; + gcc_assert (operands[1] == constm1_rtx); + return "dec{b}\t%0"; } default: - /* Use add as much as possible to replace lea for AGU optimization. */ - if (which_alternative == 2 && TARGET_OPT_AGU) - return "add{l}\t{%1, %0|%0, %1}"; + /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ + if (CONST_INT_P (operands[1]) + && INTVAL (operands[1]) < 0) + { + operands[1] = GEN_INT (-INTVAL (operands[1])); + return "sub{b}\t{%1, %0|%0, %1}"; + } + return "add{b}\t{%1, %0|%0, %1}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:QI 1 "incdec_operand" "") + (const_string "incdec") + (const_string "alu1"))) + (set (attr "memory") + (if_then_else (match_operand 1 "memory_operand" "") + (const_string "load") + (const_string "none"))) + (set_attr "mode" "QI")]) +(define_insn "*add_2" + [(set (reg FLAGS_REG) + (compare + (plus:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "%0,0") + (match_operand:SWI48 2 "" ",r")) + (const_int 0))) + (set (match_operand:SWI48 0 "nonimmediate_operand" "=r,rm") + (plus:SWI48 (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, mode, operands) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (operands[2] == const1_rtx) + return "inc{}\t%0"; + else + { + gcc_assert (operands[2] == constm1_rtx); + return "dec{}\t%0"; + } - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + default: + gcc_assert (rtx_equal_p (operands[0], operands[1])); + /* ???? In DImode, we ought to handle there the 32bit case too + - do we need new constraint? */ + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) + /* Avoid overflows. */ + && (mode != DImode + || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) { operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %0|%0, %2}"; + return "sub{}\t{%2, %0|%0, %2}"; } - return "add{l}\t{%2, %0|%0, %2}"; + return "add{}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (cond [(and (eq_attr "alternative" "2") - (eq (symbol_ref "TARGET_OPT_AGU") (const_int 0))) - (const_string "lea") - (eq_attr "alternative" "3") - (const_string "lea") - ; Current assemblers are broken and do not allow @GOTOFF in - ; ought but a memory context. - (match_operand:SI 2 "pic_symbolic_operand" "") - (const_string "lea") - (match_operand:SI 2 "incdec_operand" "") - (const_string "incdec") - ] - (const_string "alu"))) + (if_then_else (match_operand:SWI48 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) (set (attr "length_immediate") (if_then_else (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "SI")]) - -;; Convert lea to the lea pattern to avoid flags dependency. -(define_split - [(set (match_operand 0 "register_operand" "") - (plus (match_operand 1 "register_operand" "") - (match_operand 2 "nonmemory_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "reload_completed && ix86_lea_for_add_ok (PLUS, insn, operands)" - [(const_int 0)] -{ - rtx pat; - /* In -fPIC mode the constructs like (const (unspec [symbol_ref])) - may confuse gen_lowpart. */ - if (GET_MODE (operands[0]) != Pmode) - { - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[2] = gen_lowpart (Pmode, operands[2]); - } - operands[0] = gen_lowpart (SImode, operands[0]); - pat = gen_rtx_PLUS (Pmode, operands[1], operands[2]); - if (Pmode != SImode) - pat = gen_rtx_SUBREG (SImode, pat, 0); - emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); - DONE; -}) + (set_attr "mode" "")]) -;; It may seem that nonimmediate operand is proper one for operand 1. -;; The addsi_1 pattern allows nonimmediate operand at that place and -;; we take care in ix86_binary_operator_ok to not allow two memory -;; operands so proper swapping will be done in reload. This allow -;; patterns constructed from addsi_1 to match. -(define_insn "addsi_1_zext" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (zero_extend:DI - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,r") - (match_operand:SI 2 "general_operand" "g,li")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (PLUS, SImode, operands)" +;; See comment for addsi_1_zext why we do use nonimmediate_operand +(define_insn "*addsi_2_zext" + [(set (reg FLAGS_REG) + (compare + (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") + (match_operand:SI 2 "general_operand" "g")) + (const_int 0))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, SImode, operands) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" { switch (get_attr_type (insn)) { - case TYPE_LEA: - operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0)); - return "lea{l}\t{%a2, %k0|%k0, %a2}"; - case TYPE_INCDEC: if (operands[2] == const1_rtx) return "inc{l}\t%k0"; else - { + { gcc_assert (operands[2] == constm1_rtx); return "dec{l}\t%k0"; } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) && (INTVAL (operands[2]) == 128 @@ -6896,16 +6721,9 @@ } } [(set (attr "type") - (cond [(eq_attr "alternative" "1") - (const_string "lea") - ; Current assemblers are broken and do not allow @GOTOFF in - ; ought but a memory context. - (match_operand:SI 2 "pic_symbolic_operand" "") - (const_string "lea") - (match_operand:SI 2 "incdec_operand" "") - (const_string "incdec") - ] - (const_string "alu"))) + (if_then_else (match_operand:SI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) (set (attr "length_immediate") (if_then_else (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) @@ -6913,65 +6731,44 @@ (const_string "*"))) (set_attr "mode" "SI")]) -;; Convert lea to the lea pattern to avoid flags dependency. -(define_split - [(set (match_operand:DI 0 "register_operand" "") - (zero_extend:DI - (plus:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "nonmemory_operand" "")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed - && true_regnum (operands[0]) != true_regnum (operands[1])" - [(set (match_dup 0) - (zero_extend:DI (subreg:SI (plus:DI (match_dup 1) (match_dup 2)) 0)))] -{ - operands[1] = gen_lowpart (Pmode, operands[1]); - operands[2] = gen_lowpart (Pmode, operands[2]); -}) - -(define_insn "*addsi_2" +(define_insn "*addhi_2" [(set (reg FLAGS_REG) (compare - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0") - (match_operand:SI 2 "general_operand" "g,ri")) + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") + (match_operand:HI 2 "general_operand" "rmn,rn")) (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm") - (plus:SI (match_dup 1) (match_dup 2)))] + (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") + (plus:HI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, SImode, operands) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + && ix86_binary_operator_ok (PLUS, HImode, operands)" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{l}\t%0"; + return "inc{w}\t%0"; else { gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%0"; + return "dec{w}\t%0"; } default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %0|%0, %2}"; - } - return "add{l}\t{%2, %0|%0, %2}"; + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; + } + return "add{w}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:SI 2 "incdec_operand" "") + (if_then_else (match_operand:HI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -6979,64 +6776,55 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "SI")]) + (set_attr "mode" "HI")]) -;; See comment for addsi_1_zext why we do use nonimmediate_operand -(define_insn "*addsi_2_zext" +(define_insn "*addqi_2" [(set (reg FLAGS_REG) (compare - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")) + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") + (match_operand:QI 2 "general_operand" "qmn,qn")) (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, SImode, operands) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") + (plus:QI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (PLUS, QImode, operands)" { switch (get_attr_type (insn)) { case TYPE_INCDEC: if (operands[2] == const1_rtx) - return "inc{l}\t%k0"; + return "inc{b}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%k0"; + { + gcc_assert (operands[2] == constm1_rtx + || (CONST_INT_P (operands[2]) + && INTVAL (operands[2]) == 255)); + return "dec{b}\t%0"; } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %k0|%k0, %2}"; - } - return "add{l}\t{%2, %k0|%k0, %2}"; + && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{b}\t{%2, %0|%0, %2}"; + } + return "add{b}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:SI 2 "incdec_operand" "") + (if_then_else (match_operand:QI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "SI")]) + (set_attr "mode" "QI")]) -(define_insn "*addsi_3" +(define_insn "*add_3" [(set (reg FLAGS_REG) - (compare (neg:SI (match_operand:SI 2 "general_operand" "g")) - (match_operand:SI 1 "nonimmediate_operand" "%0"))) - (clobber (match_scratch:SI 0 "=r"))] + (compare + (neg:SWI48 (match_operand:SWI48 2 "" "")) + (match_operand:SWI48 1 "nonimmediate_operand" "%0"))) + (clobber (match_scratch:SWI48 0 "=r"))] "ix86_match_ccmode (insn, CCZmode) && !(MEM_P (operands[1]) && MEM_P (operands[2])) /* Current assemblers are broken and do not allow @GOTOFF in @@ -7048,30 +6836,35 @@ case TYPE_INCDEC: gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{l}\t%0"; + return "inc{}\t%0"; else { gcc_assert (operands[2] == constm1_rtx); - return "dec{l}\t%0"; + return "dec{}\t%0"; } default: gcc_assert (rtx_equal_p (operands[0], operands[1])); + /* ???? In DImode, we ought to handle there the 32bit case too + - do we need new constraint? */ /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) + /* Avoid overflows. */ + && (mode != DImode + || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) { operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %0|%0, %2}"; + return "sub{}\t{%2, %0|%0, %2}"; } - return "add{l}\t{%2, %0|%0, %2}"; + return "add{}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:SI 2 "incdec_operand" "") + (if_then_else (match_operand:SWI48 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -7079,13 +6872,14 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) ;; See comment for addsi_1_zext why we do use nonimmediate_operand (define_insn "*addsi_3_zext" [(set (reg FLAGS_REG) - (compare (neg:SI (match_operand:SI 2 "general_operand" "g")) - (match_operand:SI 1 "nonimmediate_operand" "%0"))) + (compare + (neg:SI (match_operand:SI 2 "general_operand" "g")) + (match_operand:SI 1 "nonimmediate_operand" "%0"))) (set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (plus:SI (match_dup 1) (match_dup 2))))] "TARGET_64BIT && ix86_match_ccmode (insn, CCZmode) @@ -7106,7 +6900,7 @@ } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) && (INTVAL (operands[2]) == 128 @@ -7130,47 +6924,135 @@ (const_string "*"))) (set_attr "mode" "SI")]) +(define_insn "*addhi_3" + [(set (reg FLAGS_REG) + (compare + (neg:HI (match_operand:HI 2 "general_operand" "rmn")) + (match_operand:HI 1 "nonimmediate_operand" "%0"))) + (clobber (match_scratch:HI 0 "=r"))] + "ix86_match_ccmode (insn, CCZmode) + && !(MEM_P (operands[1]) && MEM_P (operands[2]))" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{w}\t%0"; + else + { + gcc_assert (operands[2] == constm1_rtx); + return "dec{w}\t%0"; + } + + default: + /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. + Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + if (CONST_INT_P (operands[2]) + && (INTVAL (operands[2]) == 128 + || (INTVAL (operands[2]) < 0 + && INTVAL (operands[2]) != -128))) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{w}\t{%2, %0|%0, %2}"; + } + return "add{w}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set (attr "length_immediate") + (if_then_else + (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) + (const_string "1") + (const_string "*"))) + (set_attr "mode" "HI")]) + +(define_insn "*addqi_3" + [(set (reg FLAGS_REG) + (compare + (neg:QI (match_operand:QI 2 "general_operand" "qmn")) + (match_operand:QI 1 "nonimmediate_operand" "%0"))) + (clobber (match_scratch:QI 0 "=q"))] + "ix86_match_ccmode (insn, CCZmode) + && !(MEM_P (operands[1]) && MEM_P (operands[2]))" +{ + switch (get_attr_type (insn)) + { + case TYPE_INCDEC: + if (operands[2] == const1_rtx) + return "inc{b}\t%0"; + else + { + gcc_assert (operands[2] == constm1_rtx + || (CONST_INT_P (operands[2]) + && INTVAL (operands[2]) == 255)); + return "dec{b}\t%0"; + } + + default: + /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ + if (CONST_INT_P (operands[2]) + && INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{b}\t{%2, %0|%0, %2}"; + } + return "add{b}\t{%2, %0|%0, %2}"; + } +} + [(set (attr "type") + (if_then_else (match_operand:QI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) + (set_attr "mode" "QI")]) + ; For comparisons against 1, -1 and 128, we may generate better code ; by converting cmp to add, inc or dec as done by peephole2. This pattern ; is matched then. We can't accept general immediate, because for ; case of overflows, the result is messed up. -; This pattern also don't hold of 0x80000000, since the value overflows -; when negated. +; This pattern also don't hold of 0x8000000000000000, since the value +; overflows when negated. ; Also carry flag is reversed compared to cmp, so this conversion is valid ; only for comparisons not depending on it. -(define_insn "*addsi_4" + +(define_insn "*adddi_4" [(set (reg FLAGS_REG) - (compare (match_operand:SI 1 "nonimmediate_operand" "0") - (match_operand:SI 2 "const_int_operand" "n"))) - (clobber (match_scratch:SI 0 "=rm"))] - "ix86_match_ccmode (insn, CCGCmode) - && (INTVAL (operands[2]) & 0xffffffff) != 0x80000000" + (compare + (match_operand:DI 1 "nonimmediate_operand" "0") + (match_operand:DI 2 "x86_64_immediate_operand" "e"))) + (clobber (match_scratch:DI 0 "=rm"))] + "TARGET_64BIT + && ix86_match_ccmode (insn, CCGCmode)" { switch (get_attr_type (insn)) { case TYPE_INCDEC: if (operands[2] == constm1_rtx) - return "inc{l}\t%0"; + return "inc{q}\t%0"; else { gcc_assert (operands[2] == const1_rtx); - return "dec{l}\t%0"; + return "dec{q}\t%0"; } default: gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if ((INTVAL (operands[2]) == -128 || (INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) != 128))) - return "sub{l}\t{%2, %0|%0, %2}"; + && INTVAL (operands[2]) != 128)) + /* Avoid overflows. */ + && ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) + return "sub{q}\t{%2, %0|%0, %2}"; operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{l}\t{%2, %0|%0, %2}"; + return "add{q}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:SI 2 "incdec_operand" "") + (if_then_else (match_operand:DI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -7178,45 +7060,46 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "SI")]) + (set_attr "mode" "DI")]) + +; For comparisons against 1, -1 and 128, we may generate better code +; by converting cmp to add, inc or dec as done by peephole2. This pattern +; is matched then. We can't accept general immediate, because for +; case of overflows, the result is messed up. +; This pattern also don't hold of 0x80000000, since the value overflows +; when negated. +; Also carry flag is reversed compared to cmp, so this conversion is valid +; only for comparisons not depending on it. -(define_insn "*addsi_5" +(define_insn "*addsi_4" [(set (reg FLAGS_REG) (compare - (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0") - (match_operand:SI 2 "general_operand" "g")) - (const_int 0))) - (clobber (match_scratch:SI 0 "=r"))] - "ix86_match_ccmode (insn, CCGOCmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2])) - /* Current assemblers are broken and do not allow @GOTOFF in - ought but a memory context. */ - && ! pic_symbolic_operand (operands[2], VOIDmode)" + (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "const_int_operand" "n"))) + (clobber (match_scratch:SI 0 "=rm"))] + "ix86_match_ccmode (insn, CCGCmode) + && (INTVAL (operands[2]) & 0xffffffff) != 0x80000000" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - if (operands[2] == const1_rtx) + if (operands[2] == constm1_rtx) return "inc{l}\t%0"; else { - gcc_assert (operands[2] == constm1_rtx); + gcc_assert (operands[2] == const1_rtx); return "dec{l}\t%0"; } default: gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{l}\t{%2, %0|%0, %2}"; - } + if ((INTVAL (operands[2]) == -128 + || (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) != 128))) + return "sub{l}\t{%2, %0|%0, %2}"; + operands[2] = GEN_INT (-INTVAL (operands[2])); return "add{l}\t{%2, %0|%0, %2}"; } } @@ -7231,147 +7114,137 @@ (const_string "*"))) (set_attr "mode" "SI")]) -(define_expand "addhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (plus:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (PLUS, HImode, operands); DONE;") - -;; %%% After Dave's SUBREG_BYTE stuff goes in, re-enable incb %ah -;; type optimizations enabled by define-splits. This is not important -;; for PII, and in fact harmful because of partial register stalls. +; See comments above addsi_4 for details. -(define_insn "*addhi_1_lea" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r") - (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r") - (match_operand:HI 2 "general_operand" "rn,rm,ln"))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (PLUS, HImode, operands)" -{ +(define_insn "*addhi_4" + [(set (reg FLAGS_REG) + (compare + (match_operand:HI 1 "nonimmediate_operand" "0") + (match_operand:HI 2 "const_int_operand" "n"))) + (clobber (match_scratch:HI 0 "=rm"))] + "ix86_match_ccmode (insn, CCGCmode) + && (INTVAL (operands[2]) & 0xffff) != 0x8000" +{ switch (get_attr_type (insn)) { - case TYPE_LEA: - return "#"; case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{w}\t%0"; + if (operands[2] == constm1_rtx) + return "inc{w}\t%0"; else { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; + gcc_assert (operands[2] == const1_rtx); + return "dec{w}\t%0"; } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + gcc_assert (rtx_equal_p (operands[0], operands[1])); + /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } + if ((INTVAL (operands[2]) == -128 + || (INTVAL (operands[2]) > 0 + && INTVAL (operands[2]) != 128))) + return "sub{w}\t{%2, %0|%0, %2}"; + operands[2] = GEN_INT (-INTVAL (operands[2])); return "add{w}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (eq_attr "alternative" "2") - (const_string "lea") - (if_then_else (match_operand:HI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu")))) + (if_then_else (match_operand:HI 2 "incdec_operand" "") + (const_string "incdec") + (const_string "alu"))) (set (attr "length_immediate") (if_then_else (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "HI,HI,SI")]) + (set_attr "mode" "HI")]) -(define_insn "*addhi_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rn,rm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (PLUS, HImode, operands)" +; See comments above addsi_4 for details. + +(define_insn "*addqi_4" + [(set (reg FLAGS_REG) + (compare + (match_operand:QI 1 "nonimmediate_operand" "0") + (match_operand:QI 2 "const_int_operand" "n"))) + (clobber (match_scratch:QI 0 "=qm"))] + "ix86_match_ccmode (insn, CCGCmode) + && (INTVAL (operands[2]) & 0xff) != 0x80" { switch (get_attr_type (insn)) { case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{w}\t%0"; + if (operands[2] == constm1_rtx + || (CONST_INT_P (operands[2]) + && INTVAL (operands[2]) == 255)) + return "inc{b}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; + { + gcc_assert (operands[2] == const1_rtx); + return "dec{b}\t%0"; } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } - return "add{w}\t{%2, %0|%0, %2}"; + gcc_assert (rtx_equal_p (operands[0], operands[1])); + if (INTVAL (operands[2]) < 0) + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "add{b}\t{%2, %0|%0, %2}"; + } + return "sub{b}\t{%2, %0|%0, %2}"; } } [(set (attr "type") (if_then_else (match_operand:HI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "HI")]) + (set_attr "mode" "QI")]) -(define_insn "*addhi_2" +(define_insn "*add_5" [(set (reg FLAGS_REG) (compare - (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0") - (match_operand:HI 2 "general_operand" "rmn,rn")) + (plus:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "%0") + (match_operand:SWI48 2 "" "")) (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm") - (plus:HI (match_dup 1) (match_dup 2)))] + (clobber (match_scratch:SWI48 0 "=r"))] "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, HImode, operands)" + && !(MEM_P (operands[1]) && MEM_P (operands[2])) + /* Current assemblers are broken and do not allow @GOTOFF in + ought but a memory context. */ + && ! pic_symbolic_operand (operands[2], VOIDmode)" { switch (get_attr_type (insn)) { case TYPE_INCDEC: + gcc_assert (rtx_equal_p (operands[0], operands[1])); if (operands[2] == const1_rtx) - return "inc{w}\t%0"; + return "inc{}\t%0"; else { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; + gcc_assert (operands[2] == constm1_rtx); + return "dec{}\t%0"; } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + gcc_assert (rtx_equal_p (operands[0], operands[1])); + /* Make things pretty and `subl $4,%eax' rather than `addl $-4,%eax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) + /* Avoid overflows. */ + && (mode != DImode + || ((INTVAL (operands[2]) & ((((unsigned int) 1) << 31) - 1)))) && (INTVAL (operands[2]) == 128 || (INTVAL (operands[2]) < 0 && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; - } - return "add{w}\t{%2, %0|%0, %2}"; + { + operands[2] = GEN_INT (-INTVAL (operands[2])); + return "sub{}\t{%2, %0|%0, %2}"; + } + return "add{}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") + (if_then_else (match_operand:SWI48 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) (set (attr "length_immediate") @@ -7379,14 +7252,16 @@ (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) (const_string "1") (const_string "*"))) - (set_attr "mode" "HI")]) + (set_attr "mode" "")]) -(define_insn "*addhi_3" +(define_insn "*addhi_5" [(set (reg FLAGS_REG) - (compare (neg:HI (match_operand:HI 2 "general_operand" "rmn")) - (match_operand:HI 1 "nonimmediate_operand" "%0"))) + (compare + (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0") + (match_operand:HI 2 "general_operand" "rmn")) + (const_int 0))) (clobber (match_scratch:HI 0 "=r"))] - "ix86_match_ccmode (insn, CCZmode) + "ix86_match_ccmode (insn, CCGOCmode) && !(MEM_P (operands[1]) && MEM_P (operands[2]))" { switch (get_attr_type (insn)) @@ -7395,13 +7270,13 @@ if (operands[2] == const1_rtx) return "inc{w}\t%0"; else - { + { gcc_assert (operands[2] == constm1_rtx); return "dec{w}\t%0"; } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. + /* Make things pretty and `subw $4,%ax' rather than `addw $-4,%ax'. Exceptions: -128 encodes smaller than 128, so swap sign and op. */ if (CONST_INT_P (operands[2]) && (INTVAL (operands[2]) == 128 @@ -7425,57 +7300,13 @@ (const_string "*"))) (set_attr "mode" "HI")]) -; See comments above addsi_4 for details. -(define_insn "*addhi_4" - [(set (reg FLAGS_REG) - (compare (match_operand:HI 1 "nonimmediate_operand" "0") - (match_operand:HI 2 "const_int_operand" "n"))) - (clobber (match_scratch:HI 0 "=rm"))] - "ix86_match_ccmode (insn, CCGCmode) - && (INTVAL (operands[2]) & 0xffff) != 0x8000" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == constm1_rtx) - return "inc{w}\t%0"; - else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{w}\t%0"; - } - - default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if ((INTVAL (operands[2]) == -128 - || (INTVAL (operands[2]) > 0 - && INTVAL (operands[2]) != 128))) - return "sub{w}\t{%2, %0|%0, %2}"; - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{w}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "HI")]) - - -(define_insn "*addhi_5" +(define_insn "*addqi_5" [(set (reg FLAGS_REG) (compare - (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0") - (match_operand:HI 2 "general_operand" "rmn")) + (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0") + (match_operand:QI 2 "general_operand" "qmn")) (const_int 0))) - (clobber (match_scratch:HI 0 "=r"))] + (clobber (match_scratch:QI 0 "=q"))] "ix86_match_ccmode (insn, CCGOCmode) && !(MEM_P (operands[1]) && MEM_P (operands[2]))" { @@ -7483,351 +7314,69 @@ { case TYPE_INCDEC: if (operands[2] == const1_rtx) - return "inc{w}\t%0"; + return "inc{b}\t%0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return "dec{w}\t%0"; + { + gcc_assert (operands[2] == constm1_rtx + || (CONST_INT_P (operands[2]) + && INTVAL (operands[2]) == 255)); + return "dec{b}\t%0"; } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ + /* Make things pretty and `subb $4,%al' rather than `addb $-4,%al'. */ if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) + && INTVAL (operands[2]) < 0) { operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{w}\t{%2, %0|%0, %2}"; + return "sub{b}\t{%2, %0|%0, %2}"; } - return "add{w}\t{%2, %0|%0, %2}"; + return "add{b}\t{%2, %0|%0, %2}"; } } [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") + (if_then_else (match_operand:QI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "HI")]) - -(define_expand "addqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (PLUS, QImode, operands); DONE;") + (set_attr "mode" "QI")]) -;; %%% Potential partial reg stall on alternative 2. What to do? -(define_insn "*addqi_1_lea" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r,r") - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,r") - (match_operand:QI 2 "general_operand" "qn,qmn,rn,ln"))) +(define_insn "*addqi_ext_1_rex64" + [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") + (const_int 8) + (const_int 8)) + (plus:SI + (zero_extract:SI + (match_operand 1 "ext_register_operand" "0") + (const_int 8) + (const_int 8)) + (match_operand:QI 2 "nonmemory_operand" "Qn"))) (clobber (reg:CC FLAGS_REG))] - "!TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (PLUS, QImode, operands)" + "TARGET_64BIT" { - int widen = (which_alternative == 2); switch (get_attr_type (insn)) { - case TYPE_LEA: - return "#"; case TYPE_INCDEC: if (operands[2] == const1_rtx) - return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; + return "inc{b}\t%h0"; else - { - gcc_assert (operands[2] == constm1_rtx); - return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; - } + { + gcc_assert (operands[2] == constm1_rtx + || (CONST_INT_P (operands[2]) + && INTVAL (operands[2]) == 255)); + return "dec{b}\t%h0"; + } default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - if (widen) - return "sub{l}\t{%2, %k0|%k0, %2}"; - else - return "sub{b}\t{%2, %0|%0, %2}"; - } - if (widen) - return "add{l}\t{%k2, %k0|%k0, %k2}"; - else - return "add{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (eq_attr "alternative" "3") - (const_string "lea") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu")))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "QI,QI,SI,SI")]) - -(define_insn "*addqi_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r") - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0") - (match_operand:QI 2 "general_operand" "qn,qmn,rn"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_PARTIAL_REG_STALL - && ix86_binary_operator_ok (PLUS, QImode, operands)" -{ - int widen = (which_alternative == 2); - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return widen ? "inc{l}\t%k0" : "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx); - return widen ? "dec{l}\t%k0" : "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. - Exceptions: -128 encodes smaller than 128, so swap sign and op. */ - if (CONST_INT_P (operands[2]) - && (INTVAL (operands[2]) == 128 - || (INTVAL (operands[2]) < 0 - && INTVAL (operands[2]) != -128))) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - if (widen) - return "sub{l}\t{%2, %k0|%k0, %2}"; - else - return "sub{b}\t{%2, %0|%0, %2}"; - } - if (widen) - return "add{l}\t{%k2, %k0|%k0, %k2}"; - else - return "add{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set (attr "length_immediate") - (if_then_else - (and (eq_attr "type" "alu") (match_operand 2 "const128_operand" "")) - (const_string "1") - (const_string "*"))) - (set_attr "mode" "QI,QI,SI")]) - -(define_insn "*addqi_1_slp" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) - (plus:QI (match_dup 0) - (match_operand:QI 1 "general_operand" "qn,qnm"))) - (clobber (reg:CC FLAGS_REG))] - "(! TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) - && !(MEM_P (operands[0]) && MEM_P (operands[1]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[1] == const1_rtx) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[1] == constm1_rtx); - return "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'. */ - if (CONST_INT_P (operands[1]) - && INTVAL (operands[1]) < 0) - { - operands[1] = GEN_INT (-INTVAL (operands[1])); - return "sub{b}\t{%1, %0|%0, %1}"; - } - return "add{b}\t{%1, %0|%0, %1}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 1 "incdec_operand" "") - (const_string "incdec") - (const_string "alu1"))) - (set (attr "memory") - (if_then_else (match_operand 1 "memory_operand" "") - (const_string "load") - (const_string "none"))) - (set_attr "mode" "QI")]) - -(define_insn "*addqi_2" - [(set (reg FLAGS_REG) - (compare - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0") - (match_operand:QI 2 "general_operand" "qmn,qn")) - (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm") - (plus:QI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (PLUS, QImode, operands)" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ - if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) < 0) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{b}\t{%2, %0|%0, %2}"; - } - return "add{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "mode" "QI")]) - -(define_insn "*addqi_3" - [(set (reg FLAGS_REG) - (compare (neg:QI (match_operand:QI 2 "general_operand" "qmn")) - (match_operand:QI 1 "nonimmediate_operand" "%0"))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCZmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ - if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) < 0) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{b}\t{%2, %0|%0, %2}"; - } - return "add{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "mode" "QI")]) - -; See comments above addsi_4 for details. -(define_insn "*addqi_4" - [(set (reg FLAGS_REG) - (compare (match_operand:QI 1 "nonimmediate_operand" "0") - (match_operand:QI 2 "const_int_operand" "n"))) - (clobber (match_scratch:QI 0 "=qm"))] - "ix86_match_ccmode (insn, CCGCmode) - && (INTVAL (operands[2]) & 0xff) != 0x80" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == const1_rtx); - return "dec{b}\t%0"; - } - - default: - gcc_assert (rtx_equal_p (operands[0], operands[1])); - if (INTVAL (operands[2]) < 0) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "add{b}\t{%2, %0|%0, %2}"; - } - return "sub{b}\t{%2, %0|%0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:HI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "mode" "QI")]) - - -(define_insn "*addqi_5" - [(set (reg FLAGS_REG) - (compare - (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0") - (match_operand:QI 2 "general_operand" "qmn")) - (const_int 0))) - (clobber (match_scratch:QI 0 "=q"))] - "ix86_match_ccmode (insn, CCGOCmode) - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%0"; - } - - default: - /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'. */ - if (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) < 0) - { - operands[2] = GEN_INT (-INTVAL (operands[2])); - return "sub{b}\t{%2, %0|%0, %2}"; - } - return "add{b}\t{%2, %0|%0, %2}"; + return "add{b}\t{%2, %h0|%h0, %2}"; } } [(set (attr "type") (if_then_else (match_operand:QI 2 "incdec_operand" "") (const_string "incdec") (const_string "alu"))) + (set_attr "modrm" "1") (set_attr "mode" "QI")]) - (define_insn "addqi_ext_1" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) @@ -7865,43 +7414,6 @@ (set_attr "modrm" "1") (set_attr "mode" "QI")]) -(define_insn "*addqi_ext_1_rex64" - [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") - (const_int 8) - (const_int 8)) - (plus:SI - (zero_extract:SI - (match_operand 1 "ext_register_operand" "0") - (const_int 8) - (const_int 8)) - (match_operand:QI 2 "nonmemory_operand" "Qn"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" -{ - switch (get_attr_type (insn)) - { - case TYPE_INCDEC: - if (operands[2] == const1_rtx) - return "inc{b}\t%h0"; - else - { - gcc_assert (operands[2] == constm1_rtx - || (CONST_INT_P (operands[2]) - && INTVAL (operands[2]) == 255)); - return "dec{b}\t%h0"; - } - - default: - return "add{b}\t{%2, %h0|%h0, %2}"; - } -} - [(set (attr "type") - (if_then_else (match_operand:QI 2 "incdec_operand" "") - (const_string "incdec") - (const_string "alu"))) - (set_attr "modrm" "1") - (set_attr "mode" "QI")]) - (define_insn "*addqi_ext_2" [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q") (const_int 8) @@ -7921,178 +7433,271 @@ [(set_attr "type" "alu") (set_attr "mode" "QI")]) -;; The patterns that match these are at the end of this file. +;; The lea patterns for non-Pmodes needs to be matched by +;; several insns converted to real lea by splitters. -(define_expand "addxf3" - [(set (match_operand:XF 0 "register_operand" "") - (plus:XF (match_operand:XF 1 "register_operand" "") - (match_operand:XF 2 "register_operand" "")))] - "TARGET_80387" - "") +(define_insn_and_split "*lea_general_1" + [(set (match_operand 0 "register_operand" "=r") + (plus (plus (match_operand 1 "index_register_operand" "l") + (match_operand 2 "register_operand" "r")) + (match_operand 3 "immediate_operand" "i")))] + "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode + || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) + && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + && GET_MODE (operands[0]) == GET_MODE (operands[1]) + && GET_MODE (operands[0]) == GET_MODE (operands[2]) + && (GET_MODE (operands[0]) == GET_MODE (operands[3]) + || GET_MODE (operands[3]) == VOIDmode)" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx pat; + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); + operands[3] = gen_lowpart (Pmode, operands[3]); + pat = gen_rtx_PLUS (Pmode, gen_rtx_PLUS (Pmode, operands[1], operands[2]), + operands[3]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) -(define_expand "add3" - [(set (match_operand:MODEF 0 "register_operand" "") - (plus:MODEF (match_operand:MODEF 1 "register_operand" "") - (match_operand:MODEF 2 "nonimmediate_operand" "")))] - "(TARGET_80387 && X87_ENABLE_ARITH (mode)) - || (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" - "") - -;; Subtract instructions +(define_insn_and_split "*lea_general_1_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (plus:SI + (match_operand:SI 1 "index_register_operand" "l") + (match_operand:SI 2 "register_operand" "r")) + (match_operand:SI 3 "immediate_operand" "i"))))] + "TARGET_64BIT" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (plus:DI (match_dup 1) + (match_dup 2)) + (match_dup 3)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); + operands[3] = gen_lowpart (Pmode, operands[3]); +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn_and_split "*lea_general_2" + [(set (match_operand 0 "register_operand" "=r") + (plus (mult (match_operand 1 "index_register_operand" "l") + (match_operand 2 "const248_operand" "i")) + (match_operand 3 "nonmemory_operand" "ri")))] + "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode + || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) + && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + && GET_MODE (operands[0]) == GET_MODE (operands[1]) + && (GET_MODE (operands[0]) == GET_MODE (operands[3]) + || GET_MODE (operands[3]) == VOIDmode)" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx pat; + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); + pat = gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], operands[2]), + operands[3]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) + +(define_insn_and_split "*lea_general_2_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (mult:SI + (match_operand:SI 1 "index_register_operand" "l") + (match_operand:SI 2 "const248_operand" "n")) + (match_operand:SI 3 "nonmemory_operand" "ri"))))] + "TARGET_64BIT" + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (mult:DI (match_dup 1) + (match_dup 2)) + (match_dup 3)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) -;; %%% splits for subditi3 +(define_insn_and_split "*lea_general_3" + [(set (match_operand 0 "register_operand" "=r") + (plus (plus (mult (match_operand 1 "index_register_operand" "l") + (match_operand 2 "const248_operand" "i")) + (match_operand 3 "register_operand" "r")) + (match_operand 4 "immediate_operand" "i")))] + "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode + || (TARGET_64BIT && GET_MODE (operands[0]) == SImode)) + && (!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) + && GET_MODE (operands[0]) == GET_MODE (operands[1]) + && GET_MODE (operands[0]) == GET_MODE (operands[3])" + "#" + "&& reload_completed" + [(const_int 0)] +{ + rtx pat; + operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); + operands[4] = gen_lowpart (Pmode, operands[4]); + pat = gen_rtx_PLUS (Pmode, + gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], + operands[2]), + operands[3]), + operands[4]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) -(define_expand "subti3" - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (minus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "x86_64_general_operand" "")))] +(define_insn_and_split "*lea_general_3_zext" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (plus:SI (plus:SI + (mult:SI + (match_operand:SI 1 "index_register_operand" "l") + (match_operand:SI 2 "const248_operand" "n")) + (match_operand:SI 3 "register_operand" "r")) + (match_operand:SI 4 "immediate_operand" "i"))))] "TARGET_64BIT" - "ix86_expand_binary_operator (MINUS, TImode, operands); DONE;") + "#" + "&& reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (plus:DI (mult:DI (match_dup 1) + (match_dup 2)) + (match_dup 3)) + (match_dup 4)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[3] = gen_lowpart (Pmode, operands[3]); + operands[4] = gen_lowpart (Pmode, operands[4]); +} + [(set_attr "type" "lea") + (set_attr "mode" "SI")]) -(define_insn "*subti3_1" - [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o") - (minus:TI (match_operand:TI 1 "nonimmediate_operand" "0,0") - (match_operand:TI 2 "x86_64_general_operand" "roe,re"))) +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (plus:DI (match_operand:DI 1 "register_operand" "") + (match_operand:DI 2 "x86_64_nonmemory_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (MINUS, TImode, operands)" - "#") + "TARGET_64BIT && reload_completed + && ix86_lea_for_add_ok (PLUS, insn, operands)" + [(set (match_dup 0) + (plus:DI (match_dup 1) + (match_dup 2)))] + "") +;; Convert lea to the lea pattern to avoid flags dependency. (define_split - [(set (match_operand:TI 0 "nonimmediate_operand" "") - (minus:TI (match_operand:TI 1 "nonimmediate_operand" "") - (match_operand:TI 2 "x86_64_general_operand" ""))) + [(set (match_operand 0 "register_operand" "") + (plus (match_operand 1 "register_operand" "") + (match_operand 2 "nonmemory_operand" ""))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (compare:CC (match_dup 1) (match_dup 2))) - (set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2)))]) - (parallel [(set (match_dup 3) - (minus:DI (match_dup 4) - (plus:DI (ltu:DI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 5)))) - (clobber (reg:CC FLAGS_REG))])] - "split_ti (&operands[0], 3, &operands[0], &operands[3]);") + "reload_completed && ix86_lea_for_add_ok (PLUS, insn, operands)" + [(const_int 0)] +{ + rtx pat; + /* In -fPIC mode the constructs like (const (unspec [symbol_ref])) + may confuse gen_lowpart. */ + if (GET_MODE (operands[0]) != Pmode) + { + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); + } + operands[0] = gen_lowpart (SImode, operands[0]); + pat = gen_rtx_PLUS (Pmode, operands[1], operands[2]); + if (Pmode != SImode) + pat = gen_rtx_SUBREG (SImode, pat, 0); + emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat)); + DONE; +}) -;; %%% splits for subsidi3 +;; Convert lea to the lea pattern to avoid flags dependency. +(define_split + [(set (match_operand:DI 0 "register_operand" "") + (zero_extend:DI + (plus:SI (match_operand:SI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")))) + (clobber (reg:CC FLAGS_REG))] + "TARGET_64BIT && reload_completed + && true_regnum (operands[0]) != true_regnum (operands[1])" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (plus:DI (match_dup 1) (match_dup 2)) 0)))] +{ + operands[1] = gen_lowpart (Pmode, operands[1]); + operands[2] = gen_lowpart (Pmode, operands[2]); +}) + +;; Subtract instructions -(define_expand "subdi3" - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "x86_64_general_operand" "")))] +(define_expand "sub3" + [(set (match_operand:SDWIM 0 "nonimmediate_operand" "") + (minus:SDWIM (match_operand:SDWIM 1 "nonimmediate_operand" "") + (match_operand:SDWIM 2 "" "")))] "" - "ix86_expand_binary_operator (MINUS, DImode, operands); DONE;") + "ix86_expand_binary_operator (MINUS, mode, operands); DONE;") -(define_insn "*subdi3_1" - [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o") - (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:DI 2 "general_operand" "roiF,riF"))) +(define_insn_and_split "*sub3_doubleword" + [(set (match_operand: 0 "nonimmediate_operand" "=r,o") + (minus: + (match_operand: 1 "nonimmediate_operand" "0,0") + (match_operand: 2 "" "ro,r"))) (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" - "#") - -(define_split - [(set (match_operand:DI 0 "nonimmediate_operand" "") - (minus:DI (match_operand:DI 1 "nonimmediate_operand" "") - (match_operand:DI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT && reload_completed" - [(parallel [(set (reg:CC FLAGS_REG) (compare:CC (match_dup 1) (match_dup 2))) - (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))]) + "ix86_binary_operator_ok (MINUS, mode, operands)" + "#" + "reload_completed" + [(parallel [(set (reg:CC FLAGS_REG) + (compare:CC (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (minus:DWIH (match_dup 1) (match_dup 2)))]) (parallel [(set (match_dup 3) - (minus:SI (match_dup 4) - (plus:SI (ltu:SI (reg:CC FLAGS_REG) (const_int 0)) - (match_dup 5)))) + (minus:DWIH + (match_dup 4) + (plus:DWIH + (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0)) + (match_dup 5)))) (clobber (reg:CC FLAGS_REG))])] - "split_di (&operands[0], 3, &operands[0], &operands[3]);") - -(define_insn "subdi3_carry_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (plus:DI (match_operand:DI 3 "ix86_carry_flag_operator" "") - (match_operand:DI 2 "x86_64_general_operand" "re,rm")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" - "sbb{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "DI")]) - -(define_insn "*subdi_1_rex64" - [(set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT && ix86_binary_operator_ok (MINUS, DImode, operands)" - "sub{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - -(define_insn "*subdi_2_rex64" - [(set (reg FLAGS_REG) - (compare - (minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:DI 2 "x86_64_general_operand" "re,rm")) - (const_int 0))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (minus:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (MINUS, DImode, operands)" - "sub{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - -(define_insn "*subdi_3_rex63" - [(set (reg FLAGS_REG) - (compare (match_operand:DI 1 "nonimmediate_operand" "0,0") - (match_operand:DI 2 "x86_64_general_operand" "re,rm"))) - (set (match_operand:DI 0 "nonimmediate_operand" "=rm,r") - (minus:DI (match_dup 1) (match_dup 2)))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCmode) - && ix86_binary_operator_ok (MINUS, SImode, operands)" - "sub{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - -(define_insn "subqi3_carry" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") - (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (plus:QI (match_operand:QI 3 "ix86_carry_flag_operator" "") - (match_operand:QI 2 "general_operand" "qn,qm")))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (MINUS, QImode, operands)" - "sbb{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "QI")]) - -(define_insn "subhi3_carry" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") - (plus:HI (match_operand:HI 3 "ix86_carry_flag_operator" "") - (match_operand:HI 2 "general_operand" "rn,rm")))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (MINUS, HImode, operands)" - "sbb{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "mode" "HI")]) - -(define_insn "subsi3_carry" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (plus:SI (match_operand:SI 3 "ix86_carry_flag_operator" "") - (match_operand:SI 2 "general_operand" "ri,rm")))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (MINUS, SImode, operands)" - "sbb{l}\t{%2, %0|%0, %2}" + "split_ (&operands[0], 3, &operands[0], &operands[3]);") + +(define_insn "sub3_carry" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (minus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0,0") + (plus:SWI + (match_operand:SWI 3 "ix86_carry_flag_operator" "") + (match_operand:SWI 2 "" ",m")))) + (clobber (reg:CC FLAGS_REG))] + "ix86_binary_operator_ok (MINUS, mode, operands)" + "sbb{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") (set_attr "use_carry" "1") (set_attr "pent_pair" "pu") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) -(define_insn "subsi3_carry_zext" +(define_insn "*subsi3_carry_zext" [(set (match_operand:DI 0 "register_operand" "=r") (zero_extend:DI (minus:SI (match_operand:SI 1 "register_operand" "0") @@ -8105,22 +7710,28 @@ (set_attr "pent_pair" "pu") (set_attr "mode" "SI")]) -(define_expand "subsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "") - (minus:SI (match_operand:SI 1 "nonimmediate_operand" "") - (match_operand:SI 2 "general_operand" "")))] +(define_insn "*sub3_cconly_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (minus:SWI + (match_operand:SWI 0 "nonimmediate_operand" "m,") + (match_operand:SWI 1 "" ",m")) + (match_dup 0)))] "" - "ix86_expand_binary_operator (MINUS, SImode, operands); DONE;") + "cmp{}\t{%1, %0|%0, %1}" + [(set_attr "type" "icmp") + (set_attr "mode" "")]) -(define_insn "*subsi_1" - [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:SI 2 "general_operand" "ri,rm"))) +(define_insn "*sub_1" + [(set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (minus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0,0") + (match_operand:SWI 2 "" ",m"))) (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (MINUS, SImode, operands)" - "sub{l}\t{%2, %0|%0, %2}" + "ix86_binary_operator_ok (MINUS, mode, operands)" + "sub{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) (define_insn "*subsi_1_zext" [(set (match_operand:DI 0 "register_operand" "=r") @@ -8133,122 +7744,6 @@ [(set_attr "type" "alu") (set_attr "mode" "SI")]) -(define_insn "*subsi_2" - [(set (reg FLAGS_REG) - (compare - (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:SI 2 "general_operand" "ri,rm")) - (const_int 0))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (minus:SI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (MINUS, SImode, operands)" - "sub{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) - -(define_insn "*subsi_2_zext" - [(set (reg FLAGS_REG) - (compare - (minus:SI (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "general_operand" "g")) - (const_int 0))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (minus:SI (match_dup 1) - (match_dup 2))))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (MINUS, SImode, operands)" - "sub{l}\t{%2, %k0|%k0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) - -(define_insn "*subsi_3" - [(set (reg FLAGS_REG) - (compare (match_operand:SI 1 "nonimmediate_operand" "0,0") - (match_operand:SI 2 "general_operand" "ri,rm"))) - (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r") - (minus:SI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCmode) - && ix86_binary_operator_ok (MINUS, SImode, operands)" - "sub{l}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "SI")]) - -(define_insn "*subsi_3_zext" - [(set (reg FLAGS_REG) - (compare (match_operand:SI 1 "register_operand" "0") - (match_operand:SI 2 "general_operand" "g"))) - (set (match_operand:DI 0 "register_operand" "=r") - (zero_extend:DI - (minus:SI (match_dup 1) - (match_dup 2))))] - "TARGET_64BIT && ix86_match_ccmode (insn, CCmode) - && ix86_binary_operator_ok (MINUS, SImode, operands)" - "sub{l}\t{%2, %1|%1, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "DI")]) - -(define_expand "subhi3" - [(set (match_operand:HI 0 "nonimmediate_operand" "") - (minus:HI (match_operand:HI 1 "nonimmediate_operand" "") - (match_operand:HI 2 "general_operand" "")))] - "TARGET_HIMODE_MATH" - "ix86_expand_binary_operator (MINUS, HImode, operands); DONE;") - -(define_insn "*subhi_1" - [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") - (match_operand:HI 2 "general_operand" "rn,rm"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (MINUS, HImode, operands)" - "sub{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) - -(define_insn "*subhi_2" - [(set (reg FLAGS_REG) - (compare - (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0") - (match_operand:HI 2 "general_operand" "rn,rm")) - (const_int 0))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (minus:HI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (MINUS, HImode, operands)" - "sub{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) - -(define_insn "*subhi_3" - [(set (reg FLAGS_REG) - (compare (match_operand:HI 1 "nonimmediate_operand" "0,0") - (match_operand:HI 2 "general_operand" "rn,rm"))) - (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r") - (minus:HI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCmode) - && ix86_binary_operator_ok (MINUS, HImode, operands)" - "sub{w}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "HI")]) - -(define_expand "subqi3" - [(set (match_operand:QI 0 "nonimmediate_operand" "") - (minus:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "general_operand" "")))] - "TARGET_QIMODE_MATH" - "ix86_expand_binary_operator (MINUS, QImode, operands); DONE;") - -(define_insn "*subqi_1" - [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") - (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "general_operand" "qn,qm"))) - (clobber (reg:CC FLAGS_REG))] - "ix86_binary_operator_ok (MINUS, QImode, operands)" - "sub{b}\t{%2, %0|%0, %2}" - [(set_attr "type" "alu") - (set_attr "mode" "QI")]) - (define_insn "*subqi_1_slp" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q")) (minus:QI (match_dup 0) @@ -8260,122 +7755,150 @@ [(set_attr "type" "alu1") (set_attr "mode" "QI")]) -(define_insn "*subqi_2" +(define_insn "*sub_2" + [(set (reg FLAGS_REG) + (compare + (minus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0,0") + (match_operand:SWI 2 "" ",m")) + (const_int 0))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (minus:SWI (match_dup 1) (match_dup 2)))] + "ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (MINUS, mode, operands)" + "sub{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +(define_insn "*subsi_2_zext" [(set (reg FLAGS_REG) (compare - (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "general_operand" "qn,qm")) + (minus:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g")) (const_int 0))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") - (minus:QI (match_dup 1) (match_dup 2)))] - "ix86_match_ccmode (insn, CCGOCmode) - && ix86_binary_operator_ok (MINUS, QImode, operands)" - "sub{b}\t{%2, %0|%0, %2}" + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI (match_dup 1) + (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode) + && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{l}\t{%2, %k0|%k0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "QI")]) + (set_attr "mode" "SI")]) -(define_insn "*subqi_3" +(define_insn "*sub_3" [(set (reg FLAGS_REG) - (compare (match_operand:QI 1 "nonimmediate_operand" "0,0") - (match_operand:QI 2 "general_operand" "qn,qm"))) - (set (match_operand:QI 0 "nonimmediate_operand" "=qm,q") - (minus:QI (match_dup 1) (match_dup 2)))] + (compare (match_operand:SWI 1 "nonimmediate_operand" "0,0") + (match_operand:SWI 2 "" ",m"))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (minus:SWI (match_dup 1) (match_dup 2)))] "ix86_match_ccmode (insn, CCmode) - && ix86_binary_operator_ok (MINUS, QImode, operands)" - "sub{b}\t{%2, %0|%0, %2}" + && ix86_binary_operator_ok (MINUS, mode, operands)" + "sub{}\t{%2, %0|%0, %2}" [(set_attr "type" "alu") - (set_attr "mode" "QI")]) + (set_attr "mode" "")]) + +(define_insn "*subsi_3_zext" + [(set (reg FLAGS_REG) + (compare (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "general_operand" "g"))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (minus:SI (match_dup 1) + (match_dup 2))))] + "TARGET_64BIT && ix86_match_ccmode (insn, CCmode) + && ix86_binary_operator_ok (MINUS, SImode, operands)" + "sub{l}\t{%2, %1|%1, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) + + +(define_insn "*3_cc_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (plusminus:SWI + (match_operand:SWI 1 "nonimmediate_operand" "0,0") + (match_operand:SWI 2 "" ",m")) + (match_dup 1))) + (set (match_operand:SWI 0 "nonimmediate_operand" "=m,") + (plusminus:SWI (match_dup 1) (match_dup 2)))] + "ix86_binary_operator_ok (, mode, operands)" + "{}\t{%2, %0|%0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "")]) + +(define_insn "*si3_zext_cc_overflow" + [(set (reg:CCC FLAGS_REG) + (compare:CCC + (plusminus:SI + (match_operand:SI 1 "nonimmediate_operand" "0") + (match_operand:SI 2 "general_operand" "g")) + (match_dup 1))) + (set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI (plusminus:SI (match_dup 1) (match_dup 2))))] + "TARGET_64BIT && ix86_binary_operator_ok (, SImode, operands)" + "{l}\t{%2, %k0|%k0, %2}" + [(set_attr "type" "alu") + (set_attr "mode" "SI")]) ;; The patterns that match these are at the end of this file. -(define_expand "subxf3" +(define_expand "xf3" [(set (match_operand:XF 0 "register_operand" "") - (minus:XF (match_operand:XF 1 "register_operand" "") - (match_operand:XF 2 "register_operand" "")))] + (plusminus:XF + (match_operand:XF 1 "register_operand" "") + (match_operand:XF 2 "register_operand" "")))] "TARGET_80387" "") -(define_expand "sub3" +(define_expand "3" [(set (match_operand:MODEF 0 "register_operand" "") - (minus:MODEF (match_operand:MODEF 1 "register_operand" "") - (match_operand:MODEF 2 "nonimmediate_operand" "")))] + (plusminus:MODEF + (match_operand:MODEF 1 "register_operand" "") + (match_operand:MODEF 2 "nonimmediate_operand" "")))] "(TARGET_80387 && X87_ENABLE_ARITH (mode)) || (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" "") ;; Multiply instructions -(define_expand "muldi3" - [(parallel [(set (match_operand:DI 0 "register_operand" "") - (mult:DI (match_operand:DI 1 "register_operand" "") - (match_operand:DI 2 "x86_64_general_operand" ""))) +(define_expand "mul3" + [(parallel [(set (match_operand:SWIM248 0 "register_operand" "") + (mult:SWIM248 + (match_operand:SWIM248 1 "register_operand" "") + (match_operand:SWIM248 2 "" ""))) (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" + "" "") -;; On AMDFAM10 -;; IMUL reg64, reg64, imm8 Direct -;; IMUL reg64, mem64, imm8 VectorPath -;; IMUL reg64, reg64, imm32 Direct -;; IMUL reg64, mem64, imm32 VectorPath -;; IMUL reg64, reg64 Direct -;; IMUL reg64, mem64 Direct - -(define_insn "*muldi3_1_rex64" - [(set (match_operand:DI 0 "register_operand" "=r,r,r") - (mult:DI (match_operand:DI 1 "nonimmediate_operand" "%rm,rm,0") - (match_operand:DI 2 "x86_64_general_operand" "K,e,mr"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "@ - imul{q}\t{%2, %1, %0|%0, %1, %2} - imul{q}\t{%2, %1, %0|%0, %1, %2} - imul{q}\t{%2, %0|%0, %2}" - [(set_attr "type" "imul") - (set_attr "prefix_0f" "0,0,1") - (set (attr "athlon_decode") - (cond [(eq_attr "cpu" "athlon") - (const_string "vector") - (eq_attr "alternative" "1") - (const_string "vector") - (and (eq_attr "alternative" "2") - (match_operand 1 "memory_operand" "")) - (const_string "vector")] - (const_string "direct"))) - (set (attr "amdfam10_decode") - (cond [(and (eq_attr "alternative" "0,1") - (match_operand 1 "memory_operand" "")) - (const_string "vector")] - (const_string "direct"))) - (set_attr "mode" "DI")]) - -(define_expand "mulsi3" - [(parallel [(set (match_operand:SI 0 "register_operand" "") - (mult:SI (match_operand:SI 1 "register_operand" "") - (match_operand:SI 2 "general_operand" ""))) +(define_expand "mulqi3" + [(parallel [(set (match_operand:QI 0 "register_operand" "") + (mult:QI + (match_operand:QI 1 "register_operand" "") + (match_operand:QI 2 "nonimmediate_operand" ""))) (clobber (reg:CC FLAGS_REG))])] - "" + "TARGET_QIMODE_MATH" "") ;; On AMDFAM10 -;; IMUL reg32, reg32, imm8 Direct -;; IMUL reg32, mem32, imm8 VectorPath -;; IMUL reg32, reg32, imm32 Direct -;; IMUL reg32, mem32, imm32 VectorPath -;; IMUL reg32, reg32 Direct -;; IMUL reg32, mem32 Direct - -(define_insn "*mulsi3_1" - [(set (match_operand:SI 0 "register_operand" "=r,r,r") - (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%rm,rm,0") - (match_operand:SI 2 "general_operand" "K,i,mr"))) +;; IMUL reg32/64, reg32/64, imm8 Direct +;; IMUL reg32/64, mem32/64, imm8 VectorPath +;; IMUL reg32/64, reg32/64, imm32 Direct +;; IMUL reg32/64, mem32/64, imm32 VectorPath +;; IMUL reg32/64, reg32/64 Direct +;; IMUL reg32/64, mem32/64 Direct + +(define_insn "*mul3_1" + [(set (match_operand:SWI48 0 "register_operand" "=r,r,r") + (mult:SWI48 + (match_operand:SWI48 1 "nonimmediate_operand" "%rm,rm,0") + (match_operand:SWI48 2 "" "K,,mr"))) (clobber (reg:CC FLAGS_REG))] "!(MEM_P (operands[1]) && MEM_P (operands[2]))" "@ - imul{l}\t{%2, %1, %0|%0, %1, %2} - imul{l}\t{%2, %1, %0|%0, %1, %2} - imul{l}\t{%2, %0|%0, %2}" + imul{}\t{%2, %1, %0|%0, %1, %2} + imul{}\t{%2, %1, %0|%0, %1, %2} + imul{}\t{%2, %0|%0, %2}" [(set_attr "type" "imul") (set_attr "prefix_0f" "0,0,1") (set (attr "athlon_decode") @@ -8392,7 +7915,7 @@ (match_operand 1 "memory_operand" "")) (const_string "vector")] (const_string "direct"))) - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) (define_insn "*mulsi3_1_zext" [(set (match_operand:DI 0 "register_operand" "=r,r,r") @@ -8424,14 +7947,6 @@ (const_string "direct"))) (set_attr "mode" "SI")]) -(define_expand "mulhi3" - [(parallel [(set (match_operand:HI 0 "register_operand" "") - (mult:HI (match_operand:HI 1 "register_operand" "") - (match_operand:HI 2 "general_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_HIMODE_MATH" - "") - ;; On AMDFAM10 ;; IMUL reg16, reg16, imm8 VectorPath ;; IMUL reg16, mem16, imm8 VectorPath @@ -8439,12 +7954,14 @@ ;; IMUL reg16, mem16, imm16 VectorPath ;; IMUL reg16, reg16 Direct ;; IMUL reg16, mem16 Direct + (define_insn "*mulhi3_1" [(set (match_operand:HI 0 "register_operand" "=r,r,r") (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%rm,rm,0") (match_operand:HI 2 "general_operand" "K,n,mr"))) (clobber (reg:CC FLAGS_REG))] - "!(MEM_P (operands[1]) && MEM_P (operands[2]))" + "TARGET_HIMODE_MATH + && !(MEM_P (operands[1]) && MEM_P (operands[2]))" "@ imul{w}\t{%2, %1, %0|%0, %1, %2} imul{w}\t{%2, %1, %0|%0, %1, %2} @@ -8463,14 +7980,6 @@ (const_string "direct"))) (set_attr "mode" "HI")]) -(define_expand "mulqi3" - [(parallel [(set (match_operand:QI 0 "register_operand" "") - (mult:QI (match_operand:QI 1 "nonimmediate_operand" "") - (match_operand:QI 2 "register_operand" ""))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_QIMODE_MATH" - "") - ;;On AMDFAM10 ;; MUL reg8 Direct ;; MUL mem8 Direct @@ -8492,231 +8001,38 @@ (set_attr "amdfam10_decode" "direct") (set_attr "mode" "QI")]) -(define_expand "umulqihi3" - [(parallel [(set (match_operand:HI 0 "register_operand" "") - (mult:HI (zero_extend:HI - (match_operand:QI 1 "nonimmediate_operand" "")) - (zero_extend:HI - (match_operand:QI 2 "register_operand" "")))) +(define_expand "mul3" + [(parallel [(set (match_operand: 0 "register_operand" "") + (mult: + (any_extend: + (match_operand:DWIH 1 "nonimmediate_operand" "")) + (any_extend: + (match_operand:DWIH 2 "register_operand" "")))) (clobber (reg:CC FLAGS_REG))])] - "TARGET_QIMODE_MATH" + "" "") -(define_insn "*umulqihi3_1" - [(set (match_operand:HI 0 "register_operand" "=a") - (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) - (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_QIMODE_MATH - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "mul{b}\t%2" - [(set_attr "type" "imul") - (set_attr "length_immediate" "0") - (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "direct"))) - (set_attr "amdfam10_decode" "direct") - (set_attr "mode" "QI")]) - -(define_expand "mulqihi3" +(define_expand "mulqihi3" [(parallel [(set (match_operand:HI 0 "register_operand" "") - (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")) - (sign_extend:HI (match_operand:QI 2 "register_operand" "")))) + (mult:HI + (any_extend:HI + (match_operand:QI 1 "nonimmediate_operand" "")) + (any_extend:HI + (match_operand:QI 2 "register_operand" "")))) (clobber (reg:CC FLAGS_REG))])] "TARGET_QIMODE_MATH" "") -(define_insn "*mulqihi3_insn" - [(set (match_operand:HI 0 "register_operand" "=a") - (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0")) - (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_QIMODE_MATH - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "imul{b}\t%2" - [(set_attr "type" "imul") - (set_attr "length_immediate" "0") - (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "direct"))) - (set_attr "amdfam10_decode" "direct") - (set_attr "mode" "QI")]) - -(define_expand "umulditi3" - [(parallel [(set (match_operand:TI 0 "register_operand" "") - (mult:TI (zero_extend:TI - (match_operand:DI 1 "nonimmediate_operand" "")) - (zero_extend:TI - (match_operand:DI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "") - -(define_insn "*umulditi3_insn" - [(set (match_operand:TI 0 "register_operand" "=A") - (mult:TI (zero_extend:TI (match_operand:DI 1 "nonimmediate_operand" "%0")) - (zero_extend:TI (match_operand:DI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "mul{q}\t%2" - [(set_attr "type" "imul") - (set_attr "length_immediate" "0") - (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "double"))) - (set_attr "amdfam10_decode" "double") - (set_attr "mode" "DI")]) - -;; We can't use this pattern in 64bit mode, since it results in two separate 32bit registers -(define_expand "umulsidi3" - [(parallel [(set (match_operand:DI 0 "register_operand" "") - (mult:DI (zero_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "")) - (zero_extend:DI - (match_operand:SI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] - "!TARGET_64BIT" - "") - -(define_insn "*umulsidi3_insn" - [(set (match_operand:DI 0 "register_operand" "=A") - (mult:DI (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%0")) - (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "mul{l}\t%2" - [(set_attr "type" "imul") - (set_attr "length_immediate" "0") - (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "double"))) - (set_attr "amdfam10_decode" "double") - (set_attr "mode" "SI")]) - -(define_expand "mulditi3" - [(parallel [(set (match_operand:TI 0 "register_operand" "") - (mult:TI (sign_extend:TI - (match_operand:DI 1 "nonimmediate_operand" "")) - (sign_extend:TI - (match_operand:DI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "") - -(define_insn "*mulditi3_insn" - [(set (match_operand:TI 0 "register_operand" "=A") - (mult:TI (sign_extend:TI (match_operand:DI 1 "nonimmediate_operand" "%0")) - (sign_extend:TI (match_operand:DI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "imul{q}\t%2" - [(set_attr "type" "imul") - (set_attr "length_immediate" "0") - (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "double"))) - (set_attr "amdfam10_decode" "double") - (set_attr "mode" "DI")]) - -(define_expand "mulsidi3" - [(parallel [(set (match_operand:DI 0 "register_operand" "") - (mult:DI (sign_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "")) - (sign_extend:DI - (match_operand:SI 2 "register_operand" "")))) - (clobber (reg:CC FLAGS_REG))])] - "!TARGET_64BIT" - "") - -(define_insn "*mulsidi3_insn" - [(set (match_operand:DI 0 "register_operand" "=A") - (mult:DI (sign_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%0")) - (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm")))) - (clobber (reg:CC FLAGS_REG))] - "!TARGET_64BIT - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "imul{l}\t%2" - [(set_attr "type" "imul") - (set_attr "length_immediate" "0") - (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "double"))) - (set_attr "amdfam10_decode" "double") - (set_attr "mode" "SI")]) - -(define_expand "umuldi3_highpart" - [(parallel [(set (match_operand:DI 0 "register_operand" "") - (truncate:DI - (lshiftrt:TI - (mult:TI (zero_extend:TI - (match_operand:DI 1 "nonimmediate_operand" "")) - (zero_extend:TI - (match_operand:DI 2 "register_operand" ""))) - (const_int 64)))) - (clobber (match_scratch:DI 3 "")) - (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "") - -(define_insn "*umuldi3_highpart_rex64" - [(set (match_operand:DI 0 "register_operand" "=d") - (truncate:DI - (lshiftrt:TI - (mult:TI (zero_extend:TI - (match_operand:DI 1 "nonimmediate_operand" "%a")) - (zero_extend:TI - (match_operand:DI 2 "nonimmediate_operand" "rm"))) - (const_int 64)))) - (clobber (match_scratch:DI 3 "=1")) - (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT - && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "mul{q}\t%2" - [(set_attr "type" "imul") - (set_attr "length_immediate" "0") - (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "double"))) - (set_attr "amdfam10_decode" "double") - (set_attr "mode" "DI")]) - -(define_expand "umulsi3_highpart" - [(parallel [(set (match_operand:SI 0 "register_operand" "") - (truncate:SI - (lshiftrt:DI - (mult:DI (zero_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "")) - (zero_extend:DI - (match_operand:SI 2 "register_operand" ""))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "")) - (clobber (reg:CC FLAGS_REG))])] - "" - "") - -(define_insn "*umulsi3_highpart_insn" - [(set (match_operand:SI 0 "register_operand" "=d") - (truncate:SI - (lshiftrt:DI - (mult:DI (zero_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "%a")) - (zero_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "rm"))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "=1")) +(define_insn "*mul3_1" + [(set (match_operand: 0 "register_operand" "=A") + (mult: + (any_extend: + (match_operand:DWIH 1 "nonimmediate_operand" "%0")) + (any_extend: + (match_operand:DWIH 2 "nonimmediate_operand" "rm")))) (clobber (reg:CC FLAGS_REG))] "!(MEM_P (operands[1]) && MEM_P (operands[2]))" - "mul{l}\t%2" + "mul{}\t%2" [(set_attr "type" "imul") (set_attr "length_immediate" "0") (set (attr "athlon_decode") @@ -8724,60 +8040,60 @@ (const_string "vector") (const_string "double"))) (set_attr "amdfam10_decode" "double") - (set_attr "mode" "SI")]) + (set_attr "mode" "")]) -(define_insn "*umulsi3_highpart_zext" - [(set (match_operand:DI 0 "register_operand" "=d") - (zero_extend:DI (truncate:SI - (lshiftrt:DI - (mult:DI (zero_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "%a")) - (zero_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "rm"))) - (const_int 32))))) - (clobber (match_scratch:SI 3 "=1")) +(define_insn "*mulqihi3_1" + [(set (match_operand:HI 0 "register_operand" "=a") + (mult:HI + (any_extend:HI + (match_operand:QI 1 "nonimmediate_operand" "%0")) + (any_extend:HI + (match_operand:QI 2 "nonimmediate_operand" "qm")))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT + "TARGET_QIMODE_MATH && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "mul{l}\t%2" + "mul{b}\t%2" [(set_attr "type" "imul") (set_attr "length_immediate" "0") (set (attr "athlon_decode") - (if_then_else (eq_attr "cpu" "athlon") - (const_string "vector") - (const_string "double"))) - (set_attr "amdfam10_decode" "double") - (set_attr "mode" "SI")]) + (if_then_else (eq_attr "cpu" "athlon") + (const_string "vector") + (const_string "direct"))) + (set_attr "amdfam10_decode" "direct") + (set_attr "mode" "QI")]) -(define_expand "smuldi3_highpart" - [(parallel [(set (match_operand:DI 0 "register_operand" "") - (truncate:DI - (lshiftrt:TI - (mult:TI (sign_extend:TI - (match_operand:DI 1 "nonimmediate_operand" "")) - (sign_extend:TI - (match_operand:DI 2 "register_operand" ""))) - (const_int 64)))) - (clobber (match_scratch:DI 3 "")) +(define_expand "mul3_highpart" + [(parallel [(set (match_operand:SWI48 0 "register_operand" "") + (truncate:SWI48 + (lshiftrt: + (mult: + (any_extend: + (match_operand:SWI48 1 "nonimmediate_operand" "")) + (any_extend: + (match_operand:SWI48 2 "register_operand" ""))) + (match_dup 4)))) + (clobber (match_scratch:SWI48 3 "")) (clobber (reg:CC FLAGS_REG))])] - "TARGET_64BIT" - "") + "" + "operands[4] = GEN_INT (GET_MODE_BITSIZE (mode));") -(define_insn "*smuldi3_highpart_rex64" +(define_insn "*muldi3_highpart_1" [(set (match_operand:DI 0 "register_operand" "=d") (truncate:DI (lshiftrt:TI - (mult:TI (sign_extend:TI - (match_operand:DI 1 "nonimmediate_operand" "%a")) - (sign_extend:TI - (match_operand:DI 2 "nonimmediate_operand" "rm"))) + (mult:TI + (any_extend:TI + (match_operand:DI 1 "nonimmediate_operand" "%a")) + (any_extend:TI + (match_operand:DI 2 "nonimmediate_operand" "rm"))) (const_int 64)))) (clobber (match_scratch:DI 3 "=1")) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "imul{q}\t%2" + "mul{q}\t%2" [(set_attr "type" "imul") + (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") (const_string "vector") @@ -8785,34 +8101,22 @@ (set_attr "amdfam10_decode" "double") (set_attr "mode" "DI")]) -(define_expand "smulsi3_highpart" - [(parallel [(set (match_operand:SI 0 "register_operand" "") - (truncate:SI - (lshiftrt:DI - (mult:DI (sign_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "")) - (sign_extend:DI - (match_operand:SI 2 "register_operand" ""))) - (const_int 32)))) - (clobber (match_scratch:SI 3 "")) - (clobber (reg:CC FLAGS_REG))])] - "" - "") - -(define_insn "*smulsi3_highpart_insn" +(define_insn "*mulsi3_highpart_1" [(set (match_operand:SI 0 "register_operand" "=d") (truncate:SI (lshiftrt:DI - (mult:DI (sign_extend:DI - (match_operand:SI 1 "nonimmediate_operand" "%a")) - (sign_extend:DI - (match_operand:SI 2 "nonimmediate_operand" "rm"))) + (mult:DI + (any_extend:DI + (match_operand:SI 1 "nonimmediate_operand" "%a")) + (any_extend:DI + (match_operand:SI 2 "nonimmediate_operand" "rm"))) (const_int 32)))) (clobber (match_scratch:SI 3 "=1")) (clobber (reg:CC FLAGS_REG))] "!(MEM_P (operands[1]) && MEM_P (operands[2]))" - "imul{l}\t%2" + "mul{l}\t%2" [(set_attr "type" "imul") + (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") (const_string "vector") @@ -8820,21 +8124,22 @@ (set_attr "amdfam10_decode" "double") (set_attr "mode" "SI")]) -(define_insn "*smulsi3_highpart_zext" +(define_insn "*mulsi3_highpart_zext" [(set (match_operand:DI 0 "register_operand" "=d") (zero_extend:DI (truncate:SI (lshiftrt:DI - (mult:DI (sign_extend:DI + (mult:DI (any_extend:DI (match_operand:SI 1 "nonimmediate_operand" "%a")) - (sign_extend:DI + (any_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))) (const_int 32))))) (clobber (match_scratch:SI 3 "=1")) (clobber (reg:CC FLAGS_REG))] "TARGET_64BIT && !(MEM_P (operands[1]) && MEM_P (operands[2]))" - "imul{l}\t%2" + "mul{l}\t%2" [(set_attr "type" "imul") + (set_attr "length_immediate" "0") (set (attr "athlon_decode") (if_then_else (eq_attr "cpu" "athlon") (const_string "vector") @@ -8858,27 +8163,17 @@ "(TARGET_80387 && X87_ENABLE_ARITH (mode)) || (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)" "") - ;; Divide instructions -(define_insn "divqi3" - [(set (match_operand:QI 0 "register_operand" "=a") - (div:QI (match_operand:HI 1 "register_operand" "0") - (match_operand:QI 2 "nonimmediate_operand" "qm"))) - (clobber (reg:CC FLAGS_REG))] - "TARGET_QIMODE_MATH" - "idiv{b}\t%2" - [(set_attr "type" "idiv") - (set_attr "mode" "QI")]) - -(define_insn "udivqi3" +(define_insn "divqi3" [(set (match_operand:QI 0 "register_operand" "=a") - (udiv:QI (match_operand:HI 1 "register_operand" "0") - (match_operand:QI 2 "nonimmediate_operand" "qm"))) + (any_div:QI + (match_operand:HI 1 "register_operand" "0") + (match_operand:QI 2 "nonimmediate_operand" "qm"))) (clobber (reg:CC FLAGS_REG))] "TARGET_QIMODE_MATH" - "div{b}\t%2" + "div{b}\t%2" [(set_attr "type" "idiv") (set_attr "mode" "QI")]) @@ -8919,33 +8214,33 @@ ;; Divmod instructions. (define_expand "divmod4" - [(parallel [(set (match_operand:SWI248 0 "register_operand" "") - (div:SWI248 - (match_operand:SWI248 1 "register_operand" "") - (match_operand:SWI248 2 "nonimmediate_operand" ""))) - (set (match_operand:SWI248 3 "register_operand" "") - (mod:SWI248 (match_dup 1) (match_dup 2))) + [(parallel [(set (match_operand:SWIM248 0 "register_operand" "") + (div:SWIM248 + (match_operand:SWIM248 1 "register_operand" "") + (match_operand:SWIM248 2 "nonimmediate_operand" ""))) + (set (match_operand:SWIM248 3 "register_operand" "") + (mod:SWIM248 (match_dup 1) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] - "(mode != HImode) || TARGET_HIMODE_MATH" + "" "") (define_insn_and_split "*divmod4" - [(set (match_operand:SWI248 0 "register_operand" "=a") - (div:SWI248 (match_operand:SWI248 2 "register_operand" "0") - (match_operand:SWI248 3 "nonimmediate_operand" "rm"))) - (set (match_operand:SWI248 1 "register_operand" "=&d") - (mod:SWI248 (match_dup 2) (match_dup 3))) + [(set (match_operand:SWIM248 0 "register_operand" "=a") + (div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0") + (match_operand:SWIM248 3 "nonimmediate_operand" "rm"))) + (set (match_operand:SWIM248 1 "register_operand" "=&d") + (mod:SWIM248 (match_dup 2) (match_dup 3))) (clobber (reg:CC FLAGS_REG))] - "(mode != HImode) || TARGET_HIMODE_MATH" + "" "#" "&& reload_completed" [(parallel [(set (match_dup 1) - (ashiftrt:SWI248 (match_dup 4) (match_dup 5))) + (ashiftrt:SWIM248 (match_dup 4) (match_dup 5))) (clobber (reg:CC FLAGS_REG))]) (parallel [(set (match_dup 0) - (div:SWI248 (match_dup 2) (match_dup 3))) + (div:SWIM248 (match_dup 2) (match_dup 3))) (set (match_dup 1) - (mod:SWI248 (match_dup 2) (match_dup 3))) + (mod:SWIM248 (match_dup 2) (match_dup 3))) (use (match_dup 1)) (clobber (reg:CC FLAGS_REG))])] { @@ -8965,12 +8260,12 @@ (set_attr "mode" "")]) (define_insn "*divmod4_noext" - [(set (match_operand:SWI248 0 "register_operand" "=a") - (div:SWI248 (match_operand:SWI248 2 "register_operand" "0") - (match_operand:SWI248 3 "nonimmediate_operand" "rm"))) - (set (match_operand:SWI248 1 "register_operand" "=d") - (mod:SWI248 (match_dup 2) (match_dup 3))) - (use (match_operand:SWI248 4 "register_operand" "1")) + [(set (match_operand:SWIM248 0 "register_operand" "=a") + (div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0") + (match_operand:SWIM248 3 "nonimmediate_operand" "rm"))) + (set (match_operand:SWIM248 1 "register_operand" "=d") + (mod:SWIM248 (match_dup 2) (match_dup 3))) + (use (match_operand:SWIM248 4 "register_operand" "1")) (clobber (reg:CC FLAGS_REG))] "" "idiv{}\t%3" @@ -8978,31 +8273,31 @@ (set_attr "mode" "")]) (define_expand "udivmod4" - [(parallel [(set (match_operand:SWI248 0 "register_operand" "") - (udiv:SWI248 - (match_operand:SWI248 1 "register_operand" "") - (match_operand:SWI248 2 "nonimmediate_operand" ""))) - (set (match_operand:SWI248 3 "register_operand" "") - (umod:SWI248 (match_dup 1) (match_dup 2))) + [(parallel [(set (match_operand:SWIM248 0 "register_operand" "") + (udiv:SWIM248 + (match_operand:SWIM248 1 "register_operand" "") + (match_operand:SWIM248 2 "nonimmediate_operand" ""))) + (set (match_operand:SWIM248 3 "register_operand" "") + (umod:SWIM248 (match_dup 1) (match_dup 2))) (clobber (reg:CC FLAGS_REG))])] - "(mode != HImode) || TARGET_HIMODE_MATH" + "" "") (define_insn_and_split "*udivmod4" - [(set (match_operand:SWI248 0 "register_operand" "=a") - (udiv:SWI248 (match_operand:SWI248 2 "register_operand" "0") - (match_operand:SWI248 3 "nonimmediate_operand" "rm"))) - (set (match_operand:SWI248 1 "register_operand" "=&d") - (umod:SWI248 (match_dup 2) (match_dup 3))) + [(set (match_operand:SWIM248 0 "register_operand" "=a") + (udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0") + (match_operand:SWIM248 3 "nonimmediate_operand" "rm"))) + (set (match_operand:SWIM248 1 "register_operand" "=&d") + (umod:SWIM248 (match_dup 2) (match_dup 3))) (clobber (reg:CC FLAGS_REG))] - "(mode != HImode) || TARGET_HIMODE_MATH" + "" "#" "&& reload_completed" [(set (match_dup 1) (const_int 0)) (parallel [(set (match_dup 0) - (udiv:SWI248 (match_dup 2) (match_dup 3))) + (udiv:SWIM248 (match_dup 2) (match_dup 3))) (set (match_dup 1) - (umod:SWI248 (match_dup 2) (match_dup 3))) + (umod:SWIM248 (match_dup 2) (match_dup 3))) (use (match_dup 1)) (clobber (reg:CC FLAGS_REG))])] "" @@ -9010,14 +8305,14 @@ (set_attr "mode" "")]) (define_insn "*udivmod4_noext" - [(set (match_operand:SWI248 0 "register_operand" "=a") - (udiv:SWI248 (match_operand:SWI248 2 "register_operand" "0") - (match_operand:SWI248 3 "nonimmediate_operand" "rm"))) - (set (match_operand:SWI248 1 "register_operand" "=d") - (umod:SWI248 (match_dup 2) (match_dup 3))) - (use (match_operand:SWI248 4 "register_operand" "1")) + [(set (match_operand:SWIM248 0 "register_operand" "=a") + (udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0") + (match_operand:SWIM248 3 "nonimmediate_operand" "rm"))) + (set (match_operand:SWIM248 1 "register_operand" "=d") + (umod:SWIM248 (match_dup 2) (match_dup 3))) + (use (match_operand:SWIM248 4 "register_operand" "1")) (clobber (reg:CC FLAGS_REG))] - "(mode != HImode) || TARGET_HIMODE_MATH" + "" "div{}\t%3" [(set_attr "type" "idiv") (set_attr "mode" "")]) @@ -9301,7 +8596,8 @@ else if (GET_CODE (val) == SUBREG && (submode = GET_MODE (SUBREG_REG (val)), GET_MODE_BITSIZE (mode) > GET_MODE_BITSIZE (submode)) - && pos + len <= GET_MODE_BITSIZE (submode)) + && pos + len <= GET_MODE_BITSIZE (submode) + && GET_MODE_CLASS (submode) == MODE_INT) { /* Narrow a paradoxical subreg to prevent partial register stalls. */ mode = submode; @@ -14505,11 +13801,53 @@ ;; For all sCOND expanders, also expand the compare or test insn that ;; generates cc0. Generate an equality comparison if `seq' or `sne'. -;; %%% Do the expansion to SImode. If PII, do things the xor+setcc way -;; to avoid partial register stalls. Otherwise do things the setcc+movzx -;; way, which can later delete the movzx if only QImode is needed. +(define_insn_and_split "*setcc_di_1" + [(set (match_operand:DI 0 "register_operand" "=q") + (match_operator:DI 1 "ix86_comparison_operator" + [(reg FLAGS_REG) (const_int 0)]))] + "TARGET_64BIT && !TARGET_PARTIAL_REG_STALL" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (zero_extend:DI (match_dup 2)))] +{ + PUT_MODE (operands[1], QImode); + operands[2] = gen_lowpart (QImode, operands[0]); +}) + +(define_insn_and_split "*setcc_si_1_and" + [(set (match_operand:SI 0 "register_operand" "=q") + (match_operator:SI 1 "ix86_comparison_operator" + [(reg FLAGS_REG) (const_int 0)])) + (clobber (reg:CC FLAGS_REG))] + "!TARGET_PARTIAL_REG_STALL + && TARGET_ZERO_EXTEND_WITH_AND && optimize_function_for_speed_p (cfun)" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_dup 1)) + (parallel [(set (match_dup 0) (zero_extend:SI (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] +{ + PUT_MODE (operands[1], QImode); + operands[2] = gen_lowpart (QImode, operands[0]); +}) + +(define_insn_and_split "*setcc_si_1_movzbl" + [(set (match_operand:SI 0 "register_operand" "=q") + (match_operator:SI 1 "ix86_comparison_operator" + [(reg FLAGS_REG) (const_int 0)]))] + "!TARGET_PARTIAL_REG_STALL + && (!TARGET_ZERO_EXTEND_WITH_AND || optimize_function_for_size_p (cfun))" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (zero_extend:SI (match_dup 2)))] +{ + PUT_MODE (operands[1], QImode); + operands[2] = gen_lowpart (QImode, operands[0]); +}) -(define_insn "*setcc_1" +(define_insn "*setcc_qi" [(set (match_operand:QI 0 "nonimmediate_operand" "=qm") (match_operator:QI 1 "ix86_comparison_operator" [(reg FLAGS_REG) (const_int 0)]))] @@ -14518,7 +13856,7 @@ [(set_attr "type" "setcc") (set_attr "mode" "QI")]) -(define_insn "*setcc_2" +(define_insn "*setcc_qi_slp" [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm")) (match_operator:QI 1 "ix86_comparison_operator" [(reg FLAGS_REG) (const_int 0)]))] @@ -15252,12 +14590,25 @@ } [(set_attr "type" "call")]) -(define_insn "*call_pop_1" +(define_insn "*call_pop_1_esp" [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "rsm")) (match_operand:SI 1 "" "")) (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand:SI 2 "immediate_operand" "i")))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" +{ + if (constant_call_address_operand (operands[0], Pmode)) + return "call\t%P0"; + return "call\t%A0"; +} + [(set_attr "type" "call")]) + +(define_insn "*call_pop_1" + [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lsm")) + (match_operand:SI 1 "" "")) + (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) + (match_operand:SI 2 "immediate_operand" "i")))] + "!TARGET_64BIT && !TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[0], Pmode)) return "call\t%P0"; @@ -15270,7 +14621,7 @@ (match_operand:SI 1 "" "")) (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand:SI 2 "immediate_operand" "i,i")))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P0 jmp\t%A0" @@ -15308,10 +14659,21 @@ } [(set_attr "type" "call")]) -(define_insn "*call_1" +(define_insn "*call_1_esp" [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "rsm")) (match_operand 1 "" ""))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" +{ + if (constant_call_address_operand (operands[0], Pmode)) + return "call\t%P0"; + return "call\t%A0"; +} + [(set_attr "type" "call")]) + +(define_insn "*call_1" + [(call (mem:QI (match_operand:SI 0 "call_insn_operand" "lsm")) + (match_operand 1 "" ""))] + "!TARGET_64BIT && !TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[0], Pmode)) return "call\t%P0"; @@ -15322,7 +14684,7 @@ (define_insn "*sibcall_1" [(call (mem:QI (match_operand:SI 0 "sibcall_insn_operand" "s,U")) (match_operand 1 "" ""))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P0 jmp\t%A0" @@ -15331,7 +14693,7 @@ (define_insn "*call_1_rex64" [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rsm")) (match_operand 1 "" ""))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT + "TARGET_64BIT && !SIBLING_CALL_P (insn) && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC" { if (constant_call_address_operand (operands[0], Pmode)) @@ -15356,7 +14718,7 @@ (clobber (reg:TI XMM15_REG)) (clobber (reg:DI SI_REG)) (clobber (reg:DI DI_REG))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[0], Pmode)) return "call\t%P0"; @@ -15367,14 +14729,14 @@ (define_insn "*call_1_rex64_large" [(call (mem:QI (match_operand:DI 0 "call_insn_operand" "rm")) (match_operand 1 "" ""))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" "call\t%A0" [(set_attr "type" "call")]) (define_insn "*sibcall_1_rex64" [(call (mem:QI (match_operand:DI 0 "sibcall_insn_operand" "s,U")) (match_operand 1 "" ""))] - "SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P0 jmp\t%A0" @@ -15566,6 +14928,16 @@ (set_attr "length_immediate" "0") (set_attr "modrm" "0")]) +(define_insn "vswapmov" + [(set (match_operand:SI 0 "register_operand" "=r") + (match_operand:SI 1 "register_operand" "r")) + (unspec_volatile [(const_int 0)] UNSPECV_VSWAPMOV)] + "" + "movl.s\t{%1, %0|%0, %1}" + [(set_attr "length" "2") + (set_attr "length_immediate" "0") + (set_attr "modrm" "0")]) + ;; Pad to 16-byte boundary, max skip in op0. Used to avoid ;; branch prediction penalty for the third jump in a 16-byte ;; block on K8. @@ -18734,25 +18106,13 @@ && flag_unsafe_math_optimizations" "") -(define_expand "lfloordi2" - [(match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:MODEF 1 "register_operand" "")] - "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH && TARGET_64BIT - && !flag_trapping_math" -{ - if (optimize_insn_for_size_p ()) - FAIL; - ix86_expand_lfloorceil (operand0, operand1, true); - DONE; -}) - -(define_expand "lfloorsi2" - [(match_operand:SI 0 "nonimmediate_operand" "") +(define_expand "lfloor2" + [(match_operand:SWI48 0 "nonimmediate_operand" "") (match_operand:MODEF 1 "register_operand" "")] - "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH + "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH && !flag_trapping_math" { - if (optimize_insn_for_size_p () && TARGET_64BIT) + if (TARGET_64BIT && optimize_insn_for_size_p ()) FAIL; ix86_expand_lfloorceil (operand0, operand1, true); DONE; @@ -19008,20 +18368,10 @@ && flag_unsafe_math_optimizations" "") -(define_expand "lceildi2" - [(match_operand:DI 0 "nonimmediate_operand" "") - (match_operand:MODEF 1 "register_operand" "")] - "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH && TARGET_64BIT - && !flag_trapping_math" -{ - ix86_expand_lfloorceil (operand0, operand1, false); - DONE; -}) - -(define_expand "lceilsi2" - [(match_operand:SI 0 "nonimmediate_operand" "") +(define_expand "lceil2" + [(match_operand:SWI48 0 "nonimmediate_operand" "") (match_operand:MODEF 1 "register_operand" "")] - "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH + "SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH && !flag_trapping_math" { ix86_expand_lfloorceil (operand0, operand1, false); @@ -20168,22 +19518,26 @@ ;; Conditional move instructions. -(define_expand "movdicc" - [(set (match_operand:DI 0 "register_operand" "") - (if_then_else:DI (match_operand 1 "comparison_operator" "") - (match_operand:DI 2 "general_operand" "") - (match_operand:DI 3 "general_operand" "")))] - "TARGET_64BIT" +(define_expand "movcc" + [(set (match_operand:SWIM 0 "register_operand" "") + (if_then_else:SWIM (match_operand 1 "comparison_operator" "") + (match_operand:SWIM 2 "general_operand" "") + (match_operand:SWIM 3 "general_operand" "")))] + "" "if (ix86_expand_int_movcc (operands)) DONE; else FAIL;") -(define_insn "x86_movdicc_0_m1_rex64" - [(set (match_operand:DI 0 "register_operand" "=r") - (if_then_else:DI (match_operand 1 "ix86_carry_flag_operator" "") +;; Data flow gets confused by our desire for `sbbl reg,reg', and clearing +;; the register first winds up with `sbbl $0,reg', which is also weird. +;; So just document what we're doing explicitly. + +(define_insn "x86_movcc_0_m1" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (if_then_else:SWI48 (match_operand 1 "ix86_carry_flag_operator" "") (const_int -1) (const_int 0))) (clobber (reg:CC FLAGS_REG))] - "TARGET_64BIT" - "sbb{q}\t%0, %0" + "" + "sbb{}\t%0, %0" ; Since we don't have the proper number of operands for an alu insn, ; fill in all the blanks. [(set_attr "type" "alu") @@ -20191,134 +19545,56 @@ (set_attr "pent_pair" "pu") (set_attr "memory" "none") (set_attr "imm_disp" "false") - (set_attr "mode" "DI") - (set_attr "length_immediate" "0")]) - -(define_insn "*x86_movdicc_0_m1_se" - [(set (match_operand:DI 0 "register_operand" "=r") - (sign_extract:DI (match_operand 1 "ix86_carry_flag_operator" "") - (const_int 1) - (const_int 0))) - (clobber (reg:CC FLAGS_REG))] - "" - "sbb{q}\t%0, %0" - [(set_attr "type" "alu") - (set_attr "use_carry" "1") - (set_attr "pent_pair" "pu") - (set_attr "memory" "none") - (set_attr "imm_disp" "false") - (set_attr "mode" "DI") + (set_attr "mode" "") (set_attr "length_immediate" "0")]) -(define_insn "*movdicc_c_rex64" - [(set (match_operand:DI 0 "register_operand" "=r,r") - (if_then_else:DI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) - (match_operand:DI 2 "nonimmediate_operand" "rm,0") - (match_operand:DI 3 "nonimmediate_operand" "0,rm")))] - "TARGET_64BIT && TARGET_CMOVE - && !(MEM_P (operands[2]) && MEM_P (operands[3]))" - "@ - cmov%O2%C1\t{%2, %0|%0, %2} - cmov%O2%c1\t{%3, %0|%0, %3}" - [(set_attr "type" "icmov") - (set_attr "mode" "DI")]) - -(define_expand "movsicc" - [(set (match_operand:SI 0 "register_operand" "") - (if_then_else:SI (match_operand 1 "comparison_operator" "") - (match_operand:SI 2 "general_operand" "") - (match_operand:SI 3 "general_operand" "")))] - "" - "if (ix86_expand_int_movcc (operands)) DONE; else FAIL;") - -;; Data flow gets confused by our desire for `sbbl reg,reg', and clearing -;; the register first winds up with `sbbl $0,reg', which is also weird. -;; So just document what we're doing explicitly. - -(define_insn "x86_movsicc_0_m1" - [(set (match_operand:SI 0 "register_operand" "=r") - (if_then_else:SI (match_operand 1 "ix86_carry_flag_operator" "") - (const_int -1) - (const_int 0))) +(define_insn "*x86_movcc_0_m1_se" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (sign_extract:SWI48 (match_operand 1 "ix86_carry_flag_operator" "") + (const_int 1) + (const_int 0))) (clobber (reg:CC FLAGS_REG))] "" - "sbb{l}\t%0, %0" - ; Since we don't have the proper number of operands for an alu insn, - ; fill in all the blanks. + "sbb{}\t%0, %0" [(set_attr "type" "alu") (set_attr "use_carry" "1") (set_attr "pent_pair" "pu") (set_attr "memory" "none") (set_attr "imm_disp" "false") - (set_attr "mode" "SI") + (set_attr "mode" "") (set_attr "length_immediate" "0")]) -(define_insn "*x86_movsicc_0_m1_se" - [(set (match_operand:SI 0 "register_operand" "=r") - (sign_extract:SI (match_operand 1 "ix86_carry_flag_operator" "") - (const_int 1) - (const_int 0))) - (clobber (reg:CC FLAGS_REG))] +(define_insn "*x86_movcc_0_m1_neg" + [(set (match_operand:SWI48 0 "register_operand" "=r") + (neg:SWI48 (match_operand 1 "ix86_carry_flag_operator" "")))] "" - "sbb{l}\t%0, %0" + "sbb{}\t%0, %0" [(set_attr "type" "alu") (set_attr "use_carry" "1") (set_attr "pent_pair" "pu") (set_attr "memory" "none") (set_attr "imm_disp" "false") - (set_attr "mode" "SI") + (set_attr "mode" "") (set_attr "length_immediate" "0")]) -(define_insn "*movsicc_noc" - [(set (match_operand:SI 0 "register_operand" "=r,r") - (if_then_else:SI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) - (match_operand:SI 2 "nonimmediate_operand" "rm,0") - (match_operand:SI 3 "nonimmediate_operand" "0,rm")))] - "TARGET_CMOVE - && !(MEM_P (operands[2]) && MEM_P (operands[3]))" - "@ - cmov%O2%C1\t{%2, %0|%0, %2} - cmov%O2%c1\t{%3, %0|%0, %3}" - [(set_attr "type" "icmov") - (set_attr "mode" "SI")]) - -(define_expand "movhicc" - [(set (match_operand:HI 0 "register_operand" "") - (if_then_else:HI (match_operand 1 "comparison_operator" "") - (match_operand:HI 2 "general_operand" "") - (match_operand:HI 3 "general_operand" "")))] - "TARGET_HIMODE_MATH" - "if (ix86_expand_int_movcc (operands)) DONE; else FAIL;") - -(define_insn "*movhicc_noc" - [(set (match_operand:HI 0 "register_operand" "=r,r") - (if_then_else:HI (match_operator 1 "ix86_comparison_operator" - [(reg FLAGS_REG) (const_int 0)]) - (match_operand:HI 2 "nonimmediate_operand" "rm,0") - (match_operand:HI 3 "nonimmediate_operand" "0,rm")))] - "TARGET_CMOVE - && !(MEM_P (operands[2]) && MEM_P (operands[3]))" +(define_insn "*movcc_noc" + [(set (match_operand:SWI248 0 "register_operand" "=r,r") + (if_then_else:SWI248 (match_operator 1 "ix86_comparison_operator" + [(reg FLAGS_REG) (const_int 0)]) + (match_operand:SWI248 2 "nonimmediate_operand" "rm,0") + (match_operand:SWI248 3 "nonimmediate_operand" "0,rm")))] + "TARGET_CMOVE && !(MEM_P (operands[2]) && MEM_P (operands[3]))" "@ cmov%O2%C1\t{%2, %0|%0, %2} cmov%O2%c1\t{%3, %0|%0, %3}" [(set_attr "type" "icmov") - (set_attr "mode" "HI")]) - -(define_expand "movqicc" - [(set (match_operand:QI 0 "register_operand" "") - (if_then_else:QI (match_operand 1 "comparison_operator" "") - (match_operand:QI 2 "general_operand" "") - (match_operand:QI 3 "general_operand" "")))] - "TARGET_QIMODE_MATH" - "if (ix86_expand_int_movcc (operands)) DONE; else FAIL;") + (set_attr "mode" "")]) (define_insn_and_split "*movqicc_noc" [(set (match_operand:QI 0 "register_operand" "=r,r") (if_then_else:QI (match_operator 1 "ix86_comparison_operator" - [(match_operand 4 "flags_reg_operand" "") - (const_int 0)]) + [(match_operand 4 "flags_reg_operand" "") + (const_int 0)]) (match_operand:QI 2 "register_operand" "r,0") (match_operand:QI 3 "register_operand" "0,r")))] "TARGET_CMOVE && !TARGET_PARTIAL_REG_STALL" @@ -20424,6 +19700,20 @@ [(set_attr "type" "fcmov") (set_attr "mode" "XF")]) +;; All moves in XOP pcmov instructions are 128 bits and hence we restrict +;; the scalar versions to have only XMM registers as operands. + +;; XOP conditional move +(define_insn "*xop_pcmov_" + [(set (match_operand:MODEF 0 "register_operand" "=x") + (if_then_else:MODEF + (match_operand:MODEF 1 "register_operand" "x") + (match_operand:MODEF 2 "register_operand" "x") + (match_operand:MODEF 3 "register_operand" "x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, true, 1, false)" + "vpcmov\t{%1, %3, %2, %0|%0, %2, %3, %1}" + [(set_attr "type" "sse4arg")]) + ;; These versions of the min/max patterns are intentionally ignorant of ;; their behavior wrt -0.0 and NaN (via the commutative operand mark). ;; Since both the tree-level MAX_EXPR and the rtl-level SMAX operator @@ -20733,6 +20023,18 @@ DONE; }) +;; Use IOR for stack probes, this is shorter. +(define_expand "probe_stack" + [(match_operand 0 "memory_operand" "")] + "" +{ + if (GET_MODE (operands[0]) == DImode) + emit_insn (gen_iordi3 (operands[0], operands[0], const0_rtx)); + else + emit_insn (gen_iorsi3 (operands[0], operands[0], const0_rtx)); + DONE; +}) + (define_expand "builtin_setjmp_receiver" [(label_ref (match_operand 0 "" ""))] "!TARGET_64BIT && flag_pic" @@ -21236,7 +20538,9 @@ [(match_dup 0) (match_operand:SI 1 "nonmemory_operand" "")])) (clobber (reg:CC FLAGS_REG))])] - "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE" + "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE + /* Do not split stack checking probes. */ + && GET_CODE (operands[3]) != IOR && operands[1] != const0_rtx" [(set (match_dup 2) (match_dup 0)) (parallel [(set (match_dup 2) (match_op_dup 3 [(match_dup 2) (match_dup 1)])) @@ -21251,7 +20555,9 @@ [(match_operand:SI 1 "nonmemory_operand" "") (match_dup 0)])) (clobber (reg:CC FLAGS_REG))])] - "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE" + "optimize_insn_for_speed_p () && ! TARGET_READ_MODIFY_WRITE + /* Do not split stack checking probes. */ + && GET_CODE (operands[3]) != IOR && operands[1] != const0_rtx" [(set (match_dup 2) (match_dup 0)) (parallel [(set (match_dup 2) (match_op_dup 3 [(match_dup 1) (match_dup 2)])) @@ -21856,13 +21162,27 @@ } [(set_attr "type" "callv")]) -(define_insn "*call_value_pop_1" +(define_insn "*call_value_pop_1_esp" [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm")) (match_operand:SI 2 "" ""))) (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand:SI 3 "immediate_operand" "i")))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" +{ + if (constant_call_address_operand (operands[1], Pmode)) + return "call\t%P1"; + return "call\t%A1"; +} + [(set_attr "type" "callv")]) + +(define_insn "*call_value_pop_1" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lsm")) + (match_operand:SI 2 "" ""))) + (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) + (match_operand:SI 3 "immediate_operand" "i")))] + "!TARGET_64BIT && !TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[1], Pmode)) return "call\t%P1"; @@ -21876,7 +21196,7 @@ (match_operand:SI 2 "" ""))) (set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (match_operand:SI 3 "immediate_operand" "i,i")))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P1 jmp\t%A1" @@ -21925,7 +21245,7 @@ (clobber (reg:TI XMM15_REG)) (clobber (reg:DI SI_REG)) (clobber (reg:DI DI_REG))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (SIBLING_CALL_P (insn)) return "jmp\t%P1"; @@ -21934,11 +21254,23 @@ } [(set_attr "type" "callv")]) -(define_insn "*call_value_1" +(define_insn "*call_value_1_esp" [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "call_insn_operand" "rsm")) (match_operand:SI 2 "" "")))] - "!SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" +{ + if (constant_call_address_operand (operands[1], Pmode)) + return "call\t%P1"; + return "call\t%A1"; +} + [(set_attr "type" "callv")]) + +(define_insn "*call_value_1" + [(set (match_operand 0 "" "") + (call (mem:QI (match_operand:SI 1 "call_insn_operand" "lsm")) + (match_operand:SI 2 "" "")))] + "!TARGET_64BIT && !TARGET_CALL_ESP && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[1], Pmode)) return "call\t%P1"; @@ -21950,7 +21282,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:SI 1 "sibcall_insn_operand" "s,U")) (match_operand:SI 2 "" "")))] - "SIBLING_CALL_P (insn) && !TARGET_64BIT" + "!TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P1 jmp\t%A1" @@ -21960,7 +21292,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rsm")) (match_operand:DI 2 "" "")))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT + "TARGET_64BIT && !SIBLING_CALL_P (insn) && ix86_cmodel != CM_LARGE && ix86_cmodel != CM_LARGE_PIC" { if (constant_call_address_operand (operands[1], Pmode)) @@ -21974,19 +21306,19 @@ (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rsm")) (match_operand:DI 2 "" ""))) (unspec [(const_int 0)] UNSPEC_MS_TO_SYSV_CALL) - (clobber (reg:TI 27)) - (clobber (reg:TI 28)) - (clobber (reg:TI 45)) - (clobber (reg:TI 46)) - (clobber (reg:TI 47)) - (clobber (reg:TI 48)) - (clobber (reg:TI 49)) - (clobber (reg:TI 50)) - (clobber (reg:TI 51)) - (clobber (reg:TI 52)) + (clobber (reg:TI XMM6_REG)) + (clobber (reg:TI XMM7_REG)) + (clobber (reg:TI XMM8_REG)) + (clobber (reg:TI XMM9_REG)) + (clobber (reg:TI XMM10_REG)) + (clobber (reg:TI XMM11_REG)) + (clobber (reg:TI XMM12_REG)) + (clobber (reg:TI XMM13_REG)) + (clobber (reg:TI XMM14_REG)) + (clobber (reg:TI XMM15_REG)) (clobber (reg:DI SI_REG)) (clobber (reg:DI DI_REG))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" { if (constant_call_address_operand (operands[1], Pmode)) return "call\t%P1"; @@ -21998,7 +21330,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "call_insn_operand" "rm")) (match_operand:DI 2 "" "")))] - "!SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && !SIBLING_CALL_P (insn)" "call\t%A1" [(set_attr "type" "callv")]) @@ -22006,7 +21338,7 @@ [(set (match_operand 0 "" "") (call (mem:QI (match_operand:DI 1 "sibcall_insn_operand" "s,U")) (match_operand:DI 2 "" "")))] - "SIBLING_CALL_P (insn) && TARGET_64BIT" + "TARGET_64BIT && SIBLING_CALL_P (insn)" "@ jmp\t%P1 jmp\t%A1" @@ -22025,14 +21357,14 @@ (define_expand "sse_prologue_save" [(parallel [(set (match_operand:BLK 0 "" "") - (unspec:BLK [(reg:DI 21) - (reg:DI 22) - (reg:DI 23) - (reg:DI 24) - (reg:DI 25) - (reg:DI 26) - (reg:DI 27) - (reg:DI 28)] UNSPEC_SSE_PROLOGUE_SAVE)) + (unspec:BLK [(reg:DI XMM0_REG) + (reg:DI XMM1_REG) + (reg:DI XMM2_REG) + (reg:DI XMM3_REG) + (reg:DI XMM4_REG) + (reg:DI XMM5_REG) + (reg:DI XMM6_REG) + (reg:DI XMM7_REG)] UNSPEC_SSE_PROLOGUE_SAVE)) (use (match_operand:DI 1 "register_operand" "")) (use (match_operand:DI 2 "immediate_operand" "")) (use (label_ref:DI (match_operand 3 "" "")))])] @@ -22042,14 +21374,14 @@ (define_insn "*sse_prologue_save_insn" [(set (mem:BLK (plus:DI (match_operand:DI 0 "register_operand" "R") (match_operand:DI 4 "const_int_operand" "n"))) - (unspec:BLK [(reg:DI 21) - (reg:DI 22) - (reg:DI 23) - (reg:DI 24) - (reg:DI 25) - (reg:DI 26) - (reg:DI 27) - (reg:DI 28)] UNSPEC_SSE_PROLOGUE_SAVE)) + (unspec:BLK [(reg:DI XMM0_REG) + (reg:DI XMM1_REG) + (reg:DI XMM2_REG) + (reg:DI XMM3_REG) + (reg:DI XMM4_REG) + (reg:DI XMM5_REG) + (reg:DI XMM6_REG) + (reg:DI XMM7_REG)] UNSPEC_SSE_PROLOGUE_SAVE)) (use (match_operand:DI 1 "register_operand" "r")) (use (match_operand:DI 2 "const_int_operand" "i")) (use (label_ref:DI (match_operand 3 "" "X")))] @@ -22526,6 +21858,120 @@ [(set_attr "type" "other") (set_attr "length" "3")]) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; LWP instructions +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(define_insn "lwp_llwpcbhi1" + [(unspec [(match_operand:HI 0 "register_operand" "r")] + UNSPEC_LLWP_INTRINSIC)] + "TARGET_LWP" + "llwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "HI")]) + +(define_insn "lwp_llwpcbsi1" + [(unspec [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_LLWP_INTRINSIC)] + "TARGET_LWP" + "llwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "SI")]) + +(define_insn "lwp_llwpcbdi1" + [(unspec [(match_operand:DI 0 "register_operand" "r")] + UNSPEC_LLWP_INTRINSIC)] + "TARGET_LWP" + "llwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "DI")]) + +(define_insn "lwp_slwpcbhi1" + [(unspec [(match_operand:HI 0 "register_operand" "r")] + UNSPEC_SLWP_INTRINSIC)] + "TARGET_LWP" + "slwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "HI")]) + +(define_insn "lwp_slwpcbsi1" + [(unspec [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_SLWP_INTRINSIC)] + "TARGET_LWP" + "slwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "SI")]) + +(define_insn "lwp_slwpcbdi1" + [(unspec [(match_operand:DI 0 "register_operand" "r")] + UNSPEC_SLWP_INTRINSIC)] + "TARGET_LWP" + "slwpcb\t%0" + [(set_attr "type" "lwp") + (set_attr "mode" "DI")]) + +(define_insn "lwp_lwpvalhi3" + [(unspec_volatile [(match_operand:HI 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:HI 2 "const_int_operand" "")] + UNSPECV_LWPVAL_INTRINSIC)] + "TARGET_LWP" + "lwpval\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "HI")]) + +(define_insn "lwp_lwpvalsi3" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "const_int_operand" "")] + UNSPECV_LWPVAL_INTRINSIC)] + "TARGET_LWP" + "lwpval\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "SI")]) + +(define_insn "lwp_lwpvaldi3" + [(unspec_volatile [(match_operand:DI 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "const_int_operand" "")] + UNSPECV_LWPVAL_INTRINSIC)] + "TARGET_LWP" + "lwpval\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "DI")]) + +(define_insn "lwp_lwpinshi3" + [(unspec_volatile [(match_operand:HI 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:HI 2 "const_int_operand" "")] + UNSPECV_LWPINS_INTRINSIC)] + "TARGET_LWP" + "lwpins\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "HI")]) + +(define_insn "lwp_lwpinssi3" + [(unspec_volatile [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "const_int_operand" "")] + UNSPECV_LWPINS_INTRINSIC)] + "TARGET_LWP" + "lwpins\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "SI")]) + +(define_insn "lwp_lwpinsdi3" + [(unspec_volatile [(match_operand:DI 0 "register_operand" "r") + (match_operand:SI 1 "nonimmediate_operand" "rm") + (match_operand:SI 2 "const_int_operand" "")] + UNSPECV_LWPINS_INTRINSIC)] + "TARGET_LWP" + "lwpins\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "lwp") + (set_attr "mode" "DI")]) + (include "mmx.md") (include "sse.md") (include "sync.md") diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt index 9668ff6504d..dd47b7d1dc5 100644 --- a/gcc/config/i386/i386.opt +++ b/gcc/config/i386/i386.opt @@ -314,6 +314,14 @@ mfma4 Target Report Mask(ISA_FMA4) Var(ix86_isa_flags) VarExists Save Support FMA4 built-in functions and code generation +mxop +Target Report Mask(ISA_XOP) Var(ix86_isa_flags) VarExists Save +Support XOP built-in functions and code generation + +mlwp +Target Report Mask(ISA_LWP) Var(ix86_isa_flags) VarExists Save +Support LWP built-in functions and code generation + mabm Target Report Mask(ISA_ABM) Var(ix86_isa_flags) VarExists Save Support code generation of Advanced Bit Manipulation (ABM) instructions. diff --git a/gcc/config/i386/ia32intrin.h b/gcc/config/i386/ia32intrin.h index e701b19e2a8..540bc3f09ee 100644 --- a/gcc/config/i386/ia32intrin.h +++ b/gcc/config/i386/ia32intrin.h @@ -49,6 +49,7 @@ __bswapd (int __X) return __builtin_bswap32 (__X); } +#ifdef __SSE4_2__ /* 32bit accumulate CRC32 (polynomial 0x11EDC6F41) value. */ extern __inline unsigned int __attribute__((__gnu_inline__, __always_inline__, __artificial__)) @@ -70,6 +71,7 @@ __crc32d (unsigned int __C, unsigned int __V) { return __builtin_ia32_crc32si (__C, __V); } +#endif /* SSE4.2 */ /* 32bit popcnt */ extern __inline int diff --git a/gcc/config/i386/linux.h b/gcc/config/i386/linux.h index 9b51496a864..5d8e5ad2cbe 100644 --- a/gcc/config/i386/linux.h +++ b/gcc/config/i386/linux.h @@ -104,7 +104,7 @@ along with GCC; see the file COPYING3. If not see #undef ASM_SPEC #define ASM_SPEC \ - "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} \ + "%{v:-V} %{Qy:} %{!Qn:-Qy} %{n} %{T} %{Ym,*} %{Yd,*} %{Wa,*:%*} --32 \ %{!mno-sse2avx:%{mavx:-msse2avx}} %{msse2avx:%{!mavx:-msse2avx}}" #undef SUBTARGET_EXTRA_SPECS @@ -207,6 +207,9 @@ along with GCC; see the file COPYING3. If not see #define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h" +/* The stack pointer needs to be moved while checking the stack. */ +#define STACK_CHECK_MOVING_SP 1 + /* This macro may be overridden in i386/k*bsd-gnu.h. */ #define REG_NAME(reg) reg diff --git a/gcc/config/i386/linux64.h b/gcc/config/i386/linux64.h index cfa3f49e870..d07547a804f 100644 --- a/gcc/config/i386/linux64.h +++ b/gcc/config/i386/linux64.h @@ -110,6 +110,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define MD_UNWIND_SUPPORT "config/i386/linux-unwind.h" +/* The stack pointer needs to be moved while checking the stack. */ +#define STACK_CHECK_MOVING_SP 1 + /* This macro may be overridden in i386/k*bsd-gnu.h. */ #define REG_NAME(reg) reg diff --git a/gcc/config/i386/lwpintrin.h b/gcc/config/i386/lwpintrin.h new file mode 100644 index 00000000000..e5137ec24f4 --- /dev/null +++ b/gcc/config/i386/lwpintrin.h @@ -0,0 +1,109 @@ +/* Copyright (C) 2007, 2008, 2009 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef _X86INTRIN_H_INCLUDED +# error "Never use directly; include instead." +#endif + +#ifndef _LWPINTRIN_H_INCLUDED +#define _LWPINTRIN_H_INCLUDED + +#ifndef __LWP__ +# error "LWP instruction set not enabled" +#else + +extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__llwpcb16 (void *pcbAddress) +{ + __builtin_ia32_llwpcb16 (pcbAddress); +} + +extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__llwpcb32 (void *pcbAddress) +{ + __builtin_ia32_llwpcb32 (pcbAddress); +} + +extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__llwpcb64 (void *pcbAddress) +{ + __builtin_ia32_llwpcb64 (pcbAddress); +} + +extern __inline void * __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__slwpcb16 (void) +{ + return __builtin_ia32_slwpcb16 (); +} + +extern __inline void * __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__slwpcb32 (void) +{ + return __builtin_ia32_slwpcb32 (); +} + +extern __inline void * __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__slwpcb64 (void) +{ + return __builtin_ia32_slwpcb64 (); +} + +extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__lwpval16 (unsigned short data2, unsigned int data1, unsigned short flags) +{ + __builtin_ia32_lwpval16 (data2, data1, flags); +} +/* +extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__lwpval32 (unsigned int data2, unsigned int data1, unsigned int flags) +{ + __builtin_ia32_lwpval32 (data2, data1, flags); +} + +extern __inline void __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__lwpval64 (unsigned __int64 data2, unsigned int data1, unsigned int flags) +{ + __builtin_ia32_lwpval64 (data2, data1, flags); +} + +extern __inline unsigned char __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__lwpins16 (unsigned short data2, unsigned int data1, unsigned short flags) +{ + return __builtin_ia32_lwpins16 (data2, data1, flags); +} + +extern __inline unsigned char __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__lwpins32 (unsigned int data2, unsigned int data1, unsigned int flags) +{ + return __builtin_ia32_lwpins32 (data2, data1, flags); +} + +extern __inline unsigned char __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +__lwpins64 (unsigned __int64 data2, unsigned int data1, unsigned int flags) +{ + return __builtin_ia32_lwpins64 (data2, data1, flags); +} +*/ +#endif /* __LWP__ */ + +#endif /* _LWPINTRIN_H_INCLUDED */ diff --git a/gcc/config/i386/mingw.opt b/gcc/config/i386/mingw.opt index 6be904e968a..bd9a4b63035 100644 --- a/gcc/config/i386/mingw.opt +++ b/gcc/config/i386/mingw.opt @@ -21,3 +21,7 @@ Wpedantic-ms-format C ObjC C++ ObjC++ Var(warn_pedantic_ms_format) Init(1) Warning Warn about none ISO msvcrt scanf/printf width extensions + +fset-stack-executable +Common Report Var(flag_setstackexecutable) Init(1) Optimization +For nested functions on stack executable permission is set. diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h index 9dcc5ba1f67..4f8b101a7ba 100644 --- a/gcc/config/i386/mingw32.h +++ b/gcc/config/i386/mingw32.h @@ -202,6 +202,8 @@ __enable_execute_stack (void *addr) \ #undef ENABLE_EXECUTE_STACK #define ENABLE_EXECUTE_STACK MINGW_ENABLE_EXECUTE_STACK +#undef CHECK_EXECUTE_STACK_ENABLED +#define CHECK_EXECUTE_STACK_ENABLED flag_setstackexecutable #ifdef IN_LIBGCC2 #include diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md index f9a4744d1de..dee6df9fa01 100644 --- a/gcc/config/i386/predicates.md +++ b/gcc/config/i386/predicates.md @@ -561,7 +561,9 @@ ;; Test for a valid operand for a call instruction. (define_predicate "call_insn_operand" (ior (match_operand 0 "constant_call_address_operand") - (ior (match_operand 0 "register_no_elim_operand") + (ior (and (match_operand 0 "register_no_elim_operand") + (ior (match_test "TARGET_CALL_ESP") + (match_operand 0 "index_register_operand"))) (match_operand 0 "memory_operand")))) ;; Similarly, but for tail calls, in which we cannot allow memory references. diff --git a/gcc/config/i386/sol2-unwind.h b/gcc/config/i386/sol2-unwind.h new file mode 100644 index 00000000000..41ffb03b6cd --- /dev/null +++ b/gcc/config/i386/sol2-unwind.h @@ -0,0 +1,208 @@ +/* DWARF2 EH unwinding support for AMD x86-64 and x86. + Copyright (C) 2009 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 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* Do code reading to identify a signal frame, and set the frame + state data appropriately. See unwind-dw2.c for the structs. */ + +#include + +#ifdef __x86_64__ + +#define MD_FALLBACK_FRAME_STATE_FOR x86_64_fallback_frame_state + +static _Unwind_Reason_Code +x86_64_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + unsigned char *pc = context->ra; + mcontext_t *mctx; + long new_cfa; + + if (/* Solaris 2.10 + ------------ + <__sighndlr+0>: push %rbp + <__sighndlr+1>: mov %rsp,%rbp + <__sighndlr+4>: callq *%rcx + <__sighndlr+6>: leaveq <--- PC + <__sighndlr+7>: retq */ + *(unsigned long *)(pc - 6) == 0xc3c9d1ffe5894855) + /* We need to move up four frames (the kernel frame, the signal frame, + the call_user_handler frame and the __sighndlr frame). Two of them + have the minimum stack frame size (kernel and __sighndlr frames), + the signal frame has a stack frame size of 32 and there is another + with a stack frame size of 112 bytes (the call_user_handler frame). + The ucontext_t structure is after this offset. */ + { + int off = 16 + 16 + 32 + 112; + mctx = &((ucontext_t *) (context->cfa + off))->uc_mcontext; + } + else + return _URC_END_OF_STACK; + + new_cfa = mctx->gregs[REG_RSP]; + + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = 7; + fs->regs.cfa_offset = new_cfa - (long) context->cfa; + + /* The SVR4 register numbering macros aren't usable in libgcc. */ + fs->regs.reg[0].how = REG_SAVED_OFFSET; + fs->regs.reg[0].loc.offset = (long)&mctx->gregs[REG_RAX] - new_cfa; + fs->regs.reg[1].how = REG_SAVED_OFFSET; + fs->regs.reg[1].loc.offset = (long)&mctx->gregs[REG_RDX] - new_cfa; + fs->regs.reg[2].how = REG_SAVED_OFFSET; + fs->regs.reg[2].loc.offset = (long)&mctx->gregs[REG_RCX] - new_cfa; + fs->regs.reg[3].how = REG_SAVED_OFFSET; + fs->regs.reg[3].loc.offset = (long)&mctx->gregs[REG_RBX] - new_cfa; + fs->regs.reg[4].how = REG_SAVED_OFFSET; + fs->regs.reg[4].loc.offset = (long)&mctx->gregs[REG_RSI] - new_cfa; + fs->regs.reg[5].how = REG_SAVED_OFFSET; + fs->regs.reg[5].loc.offset = (long)&mctx->gregs[REG_RDI] - new_cfa; + fs->regs.reg[6].how = REG_SAVED_OFFSET; + fs->regs.reg[6].loc.offset = (long)&mctx->gregs[REG_RBP] - new_cfa; + fs->regs.reg[8].how = REG_SAVED_OFFSET; + fs->regs.reg[8].loc.offset = (long)&mctx->gregs[REG_R8] - new_cfa; + fs->regs.reg[9].how = REG_SAVED_OFFSET; + fs->regs.reg[9].loc.offset = (long)&mctx->gregs[REG_R9] - new_cfa; + fs->regs.reg[10].how = REG_SAVED_OFFSET; + fs->regs.reg[10].loc.offset = (long)&mctx->gregs[REG_R10] - new_cfa; + fs->regs.reg[11].how = REG_SAVED_OFFSET; + fs->regs.reg[11].loc.offset = (long)&mctx->gregs[REG_R11] - new_cfa; + fs->regs.reg[12].how = REG_SAVED_OFFSET; + fs->regs.reg[12].loc.offset = (long)&mctx->gregs[REG_R12] - new_cfa; + fs->regs.reg[13].how = REG_SAVED_OFFSET; + fs->regs.reg[13].loc.offset = (long)&mctx->gregs[REG_R13] - new_cfa; + fs->regs.reg[14].how = REG_SAVED_OFFSET; + fs->regs.reg[14].loc.offset = (long)&mctx->gregs[REG_R14] - new_cfa; + fs->regs.reg[15].how = REG_SAVED_OFFSET; + fs->regs.reg[15].loc.offset = (long)&mctx->gregs[REG_R15] - new_cfa; + fs->regs.reg[16].how = REG_SAVED_OFFSET; + fs->regs.reg[16].loc.offset = (long)&mctx->gregs[REG_RIP] - new_cfa; + fs->retaddr_column = 16; + fs->signal_frame = 1; + + return _URC_NO_REASON; +} + +#else + +#define MD_FALLBACK_FRAME_STATE_FOR x86_fallback_frame_state + +static _Unwind_Reason_Code +x86_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + unsigned char *pc = context->ra; + mcontext_t *mctx; + long new_cfa; + + if (/* Solaris 2.8 - single thread + ------------------------- + : mov 0x10(%ebp),%esi + : push %esi + : pushl 0xc(%ebp) + : mov 0x8(%ebp),%ecx + : push %ecx + : mov offset(%ebx),%eax + : call *(%eax,%ecx,4) + : add $0xc,%esp <--- PC + : push %esi ... */ + (*(unsigned long *)(pc - 20) == 0x5610758b + && *(unsigned long *)(pc - 16) == 0x8b0c75ff + && *(unsigned long *)(pc - 12) == 0x8b51084d + && *(unsigned char *)(pc - 8) == 0x83 + && *(unsigned long *)(pc - 4) == 0x8814ff00 + && *(unsigned long *)(pc - 0) == 0x560cc483) + + || /* Solaris 2.8 - multi thread + --------------------------- + <__sighndlr+0>: push %ebp + <__sighndlr+1>: mov %esp,%ebp + <__sighndlr+3>: pushl 0x10(%ebp) + <__sighndlr+6>: pushl 0xc(%ebp) + <__sighndlr+9>: pushl 0x8(%ebp) + <__sighndlr+12>: call *0x14(%ebp) + <__sighndlr+15>: leave <--- PC */ + (*(unsigned long *)(pc - 15) == 0xffec8b55 + && *(unsigned long *)(pc - 11) == 0x75ff1075 + && *(unsigned long *)(pc - 7) == 0x0875ff0c + && *(unsigned long *)(pc - 3) == 0xc91455ff) + + || /* Solaris 2.10 + ------------ + <__sighndlr+0>: push %ebp + <__sighndlr+1>: mov %esp,%ebp + <__sighndlr+3>: pushl 0x10(%ebp) + <__sighndlr+6>: pushl 0xc(%ebp) + <__sighndlr+9>: pushl 0x8(%ebp) + <__sighndlr+12>: call *0x14(%ebp) + <__sighndlr+15>: add $0xc,%esp <--- PC + <__sighndlr+18>: leave + <__sighndlr+19>: ret */ + (*(unsigned long *)(pc - 15) == 0xffec8b55 + && *(unsigned long *)(pc - 11) == 0x75ff1075 + && *(unsigned long *)(pc - 7) == 0x0875ff0c + && *(unsigned long *)(pc - 3) == 0x831455ff + && *(unsigned long *)(pc + 1) == 0xc3c90cc4)) + { + struct handler_args { + int signo; + siginfo_t *sip; + ucontext_t *ucontext; + } *handler_args = context->cfa; + mctx = &handler_args->ucontext->uc_mcontext; + } + else + return _URC_END_OF_STACK; + + new_cfa = mctx->gregs[UESP]; + + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = 4; + fs->regs.cfa_offset = new_cfa - (long) context->cfa; + + /* The SVR4 register numbering macros aren't usable in libgcc. */ + fs->regs.reg[0].how = REG_SAVED_OFFSET; + fs->regs.reg[0].loc.offset = (long)&mctx->gregs[EAX] - new_cfa; + fs->regs.reg[3].how = REG_SAVED_OFFSET; + fs->regs.reg[3].loc.offset = (long)&mctx->gregs[EBX] - new_cfa; + fs->regs.reg[1].how = REG_SAVED_OFFSET; + fs->regs.reg[1].loc.offset = (long)&mctx->gregs[ECX] - new_cfa; + fs->regs.reg[2].how = REG_SAVED_OFFSET; + fs->regs.reg[2].loc.offset = (long)&mctx->gregs[EDX] - new_cfa; + fs->regs.reg[6].how = REG_SAVED_OFFSET; + fs->regs.reg[6].loc.offset = (long)&mctx->gregs[ESI] - new_cfa; + fs->regs.reg[7].how = REG_SAVED_OFFSET; + fs->regs.reg[7].loc.offset = (long)&mctx->gregs[EDI] - new_cfa; + fs->regs.reg[5].how = REG_SAVED_OFFSET; + fs->regs.reg[5].loc.offset = (long)&mctx->gregs[EBP] - new_cfa; + fs->regs.reg[8].how = REG_SAVED_OFFSET; + fs->regs.reg[8].loc.offset = (long)&mctx->gregs[EIP] - new_cfa; + fs->retaddr_column = 8; + fs->signal_frame = 1; + + return _URC_NO_REASON; +} + +#endif diff --git a/gcc/config/i386/sol2.h b/gcc/config/i386/sol2.h index 4c2dfe975cf..f062280fd18 100644 --- a/gcc/config/i386/sol2.h +++ b/gcc/config/i386/sol2.h @@ -118,3 +118,5 @@ along with GCC; see the file COPYING3. If not see #ifndef TARGET_GNU_LD #define USE_HIDDEN_LINKONCE 0 #endif + +#define MD_UNWIND_SUPPORT "config/i386/sol2-unwind.h" diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md index e90296512ad..bad39bb69c8 100644 --- a/gcc/config/i386/sse.md +++ b/gcc/config/i386/sse.md @@ -86,6 +86,9 @@ (define_mode_attr ssemodesuffixf2c [(V4SF "s") (V2DF "d")]) +;; Mapping of the max integer size for xop rotate immediate constraint +(define_mode_attr sserotatemax [(V16QI "7") (V8HI "15") (V4SI "31") (V2DI "63")]) + ;; Mapping of vector modes back to the scalar modes (define_mode_attr ssescalarmode [(V4SF "SF") (V2DF "DF") (V16QI "QI") (V8HI "HI") @@ -1455,7 +1458,8 @@ (match_operator:SSEMODEF4 3 "sse_comparison_operator" [(match_operand:SSEMODEF4 1 "register_operand" "0") (match_operand:SSEMODEF4 2 "nonimmediate_operand" "xm")]))] - "(SSE_FLOAT_MODE_P (mode) || SSE_VEC_FLOAT_MODE_P (mode))" + "!TARGET_XOP + && (SSE_FLOAT_MODE_P (mode) || SSE_VEC_FLOAT_MODE_P (mode))" "cmp%D3\t{%2, %0|%0, %2}" [(set_attr "type" "ssecmp") (set_attr "length_immediate" "1") @@ -5614,7 +5618,7 @@ (match_operand:V4SI 2 "register_operand" "")))] "TARGET_SSE2" { - if (TARGET_SSE4_1) + if (TARGET_SSE4_1 || TARGET_XOP) ix86_fixup_binary_operands_no_copy (MULT, V4SImode, operands); }) @@ -5643,7 +5647,7 @@ [(set (match_operand:V4SI 0 "register_operand" "") (mult:V4SI (match_operand:V4SI 1 "register_operand" "") (match_operand:V4SI 2 "register_operand" "")))] - "TARGET_SSE2 && !TARGET_SSE4_1 + "TARGET_SSE2 && !TARGET_SSE4_1 && !TARGET_XOP && can_create_pseudo_p ()" "#" "&& 1" @@ -5705,6 +5709,42 @@ rtx t1, t2, t3, t4, t5, t6, thirtytwo; rtx op0, op1, op2; + if (TARGET_XOP) + { + /* op1: A,B,C,D, op2: E,F,G,H */ + op0 = operands[0]; + op1 = gen_lowpart (V4SImode, operands[1]); + op2 = gen_lowpart (V4SImode, operands[2]); + t1 = gen_reg_rtx (V4SImode); + t2 = gen_reg_rtx (V4SImode); + t3 = gen_reg_rtx (V4SImode); + t4 = gen_reg_rtx (V2DImode); + t5 = gen_reg_rtx (V2DImode); + + /* t1: B,A,D,C */ + emit_insn (gen_sse2_pshufd_1 (t1, op1, + GEN_INT (1), + GEN_INT (0), + GEN_INT (3), + GEN_INT (2))); + + /* t2: 0 */ + emit_move_insn (t2, CONST0_RTX (V4SImode)); + + /* t3: (B*E),(A*F),(D*G),(C*H) */ + emit_insn (gen_xop_pmacsdd (t3, t1, op2, t2)); + + /* t4: (B*E)+(A*F), (D*G)+(C*H) */ + emit_insn (gen_xop_phadddq (t4, t3)); + + /* t5: ((B*E)+(A*F))<<32, ((D*G)+(C*H))<<32 */ + emit_insn (gen_ashlv2di3 (t5, t4, GEN_INT (32))); + + /* op0: (((B*E)+(A*F))<<32)+(B*F), (((D*G)+(C*H))<<32)+(D*H) */ + emit_insn (gen_xop_pmacsdql (op0, op1, op2, t5)); + DONE; + } + op0 = operands[0]; op1 = operands[1]; op2 = operands[2]; @@ -5820,6 +5860,56 @@ DONE; }) +(define_expand "vec_widen_smult_hi_v4si" + [(match_operand:V2DI 0 "register_operand" "") + (match_operand:V4SI 1 "register_operand" "") + (match_operand:V4SI 2 "register_operand" "")] + "TARGET_XOP" +{ + rtx t1, t2; + + t1 = gen_reg_rtx (V4SImode); + t2 = gen_reg_rtx (V4SImode); + + emit_insn (gen_sse2_pshufd_1 (t1, operands[1], + GEN_INT (0), + GEN_INT (2), + GEN_INT (1), + GEN_INT (3))); + emit_insn (gen_sse2_pshufd_1 (t2, operands[2], + GEN_INT (0), + GEN_INT (2), + GEN_INT (1), + GEN_INT (3))); + emit_insn (gen_xop_mulv2div2di3_high (operands[0], t1, t2)); + DONE; +}) + +(define_expand "vec_widen_smult_lo_v4si" + [(match_operand:V2DI 0 "register_operand" "") + (match_operand:V4SI 1 "register_operand" "") + (match_operand:V4SI 2 "register_operand" "")] + "TARGET_XOP" +{ + rtx t1, t2; + + t1 = gen_reg_rtx (V4SImode); + t2 = gen_reg_rtx (V4SImode); + + emit_insn (gen_sse2_pshufd_1 (t1, operands[1], + GEN_INT (0), + GEN_INT (2), + GEN_INT (1), + GEN_INT (3))); + emit_insn (gen_sse2_pshufd_1 (t2, operands[2], + GEN_INT (0), + GEN_INT (2), + GEN_INT (1), + GEN_INT (3))); + emit_insn (gen_xop_mulv2div2di3_low (operands[0], t1, t2)); + DONE; +}) + (define_expand "vec_widen_umult_hi_v4si" [(match_operand:V2DI 0 "register_operand" "") (match_operand:V4SI 1 "register_operand" "") @@ -6217,7 +6307,7 @@ (eq:SSEMODE124 (match_operand:SSEMODE124 1 "nonimmediate_operand" "") (match_operand:SSEMODE124 2 "nonimmediate_operand" "")))] - "TARGET_SSE2" + "TARGET_SSE2 && !TARGET_XOP " "ix86_fixup_binary_operands_no_copy (EQ, mode, operands);") (define_insn "*avx_eq3" @@ -6240,7 +6330,7 @@ (eq:SSEMODE124 (match_operand:SSEMODE124 1 "nonimmediate_operand" "%0") (match_operand:SSEMODE124 2 "nonimmediate_operand" "xm")))] - "TARGET_SSE2 + "TARGET_SSE2 && !TARGET_XOP && ix86_binary_operator_ok (EQ, mode, operands)" "pcmpeq\t{%2, %0|%0, %2}" [(set_attr "type" "ssecmp") @@ -6286,7 +6376,7 @@ (gt:SSEMODE124 (match_operand:SSEMODE124 1 "register_operand" "0") (match_operand:SSEMODE124 2 "nonimmediate_operand" "xm")))] - "TARGET_SSE2" + "TARGET_SSE2 && !TARGET_XOP" "pcmpgt\t{%2, %0|%0, %2}" [(set_attr "type" "ssecmp") (set_attr "prefix_data16" "1") @@ -10364,6 +10454,1445 @@ (set_attr "prefix" "maybe_vex") (set_attr "mode" "TI")]) +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; XOP instructions +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; XOP parallel integer multiply/add instructions. +;; Note the instruction does not allow the value being added to be a memory +;; operation. However by pretending via the nonimmediate_operand predicate +;; that it does and splitting it later allows the following to be recognized: +;; a[i] = b[i] * c[i] + d[i]; +(define_insn "xop_pmacsww" + [(set (match_operand:V8HI 0 "register_operand" "=x,x,x") + (plus:V8HI + (mult:V8HI + (match_operand:V8HI 1 "nonimmediate_operand" "%x,x,xm") + (match_operand:V8HI 2 "nonimmediate_operand" "x,xm,x")) + (match_operand:V8HI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 2, true)" + "@ + vpmacsww\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsww\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsww\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +;; Split pmacsww with two memory operands into a load and the pmacsww. +(define_split + [(set (match_operand:V8HI 0 "register_operand" "") + (plus:V8HI + (mult:V8HI (match_operand:V8HI 1 "nonimmediate_operand" "") + (match_operand:V8HI 2 "nonimmediate_operand" "")) + (match_operand:V8HI 3 "nonimmediate_operand" "")))] + "TARGET_XOP + && !ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true) + && ix86_fma4_valid_op_p (operands, insn, 4, false, 2, true) + && !reg_mentioned_p (operands[0], operands[1]) + && !reg_mentioned_p (operands[0], operands[2]) + && !reg_mentioned_p (operands[0], operands[3])" + [(const_int 0)] +{ + ix86_expand_fma4_multiple_memory (operands, 4, V8HImode); + emit_insn (gen_xop_pmacsww (operands[0], operands[1], operands[2], + operands[3])); + DONE; +}) + +(define_insn "xop_pmacssww" + [(set (match_operand:V8HI 0 "register_operand" "=x,x,x") + (ss_plus:V8HI + (mult:V8HI (match_operand:V8HI 1 "nonimmediate_operand" "%x,x,m") + (match_operand:V8HI 2 "nonimmediate_operand" "x,m,x")) + (match_operand:V8HI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacssww\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssww\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssww\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +;; Note the instruction does not allow the value being added to be a memory +;; operation. However by pretending via the nonimmediate_operand predicate +;; that it does and splitting it later allows the following to be recognized: +;; a[i] = b[i] * c[i] + d[i]; +(define_insn "xop_pmacsdd" + [(set (match_operand:V4SI 0 "register_operand" "=x,x,x") + (plus:V4SI + (mult:V4SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x")) + (match_operand:V4SI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 2, true)" + "@ + vpmacsdd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsdd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsdd\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +;; Split pmacsdd with two memory operands into a load and the pmacsdd. +(define_split + [(set (match_operand:V4SI 0 "register_operand" "") + (plus:V4SI + (mult:V4SI (match_operand:V4SI 1 "nonimmediate_operand" "") + (match_operand:V4SI 2 "nonimmediate_operand" "")) + (match_operand:V4SI 3 "nonimmediate_operand" "")))] + "TARGET_XOP + && !ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true) + && ix86_fma4_valid_op_p (operands, insn, 4, false, 2, true) + && !reg_mentioned_p (operands[0], operands[1]) + && !reg_mentioned_p (operands[0], operands[2]) + && !reg_mentioned_p (operands[0], operands[3])" + [(const_int 0)] +{ + ix86_expand_fma4_multiple_memory (operands, 4, V4SImode); + emit_insn (gen_xop_pmacsdd (operands[0], operands[1], operands[2], + operands[3])); + DONE; +}) + +(define_insn "xop_pmacssdd" + [(set (match_operand:V4SI 0 "register_operand" "=x,x,x") + (ss_plus:V4SI + (mult:V4SI (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x")) + (match_operand:V4SI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacssdd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssdd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssdd\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn "xop_pmacssdql" + [(set (match_operand:V2DI 0 "register_operand" "=x,x,x") + (ss_plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 1) + (const_int 3)]))) + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 1) + (const_int 3)]))) + (match_operand:V2DI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacssdql\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssdql\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssdql\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn "xop_pmacssdqh" + [(set (match_operand:V2DI 0 "register_operand" "=x,x,x") + (ss_plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 0) + (const_int 2)])))) + (match_operand:V2DI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacssdqh\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssdqh\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacssdqh\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn "xop_pmacsdql" + [(set (match_operand:V2DI 0 "register_operand" "=x,x,x") + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 1) + (const_int 3)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 1) + (const_int 3)])))) + (match_operand:V2DI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacsdql\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsdql\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsdql\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn_and_split "*xop_pmacsdql_mem" + [(set (match_operand:V2DI 0 "register_operand" "=&x,&x,&x") + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 1) + (const_int 3)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 1) + (const_int 3)])))) + (match_operand:V2DI 3 "memory_operand" "m,m,m")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, -1, true)" + "#" + "&& (reload_completed + || (!reg_mentioned_p (operands[0], operands[1]) + && !reg_mentioned_p (operands[0], operands[2])))" + [(set (match_dup 0) + (match_dup 3)) + (set (match_dup 0) + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 2) + (parallel [(const_int 1) + (const_int 3)])))) + (match_dup 0)))]) + +;; We don't have a straight 32-bit parallel multiply and extend on XOP, so +;; fake it with a multiply/add. In general, we expect the define_split to +;; occur before register allocation, so we have to handle the corner case where +;; the target is the same as operands 1/2 +(define_insn_and_split "xop_mulv2div2di3_low" + [(set (match_operand:V2DI 0 "register_operand" "=&x") + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x") + (parallel [(const_int 1) + (const_int 3)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "xm") + (parallel [(const_int 1) + (const_int 3)])))))] + "TARGET_XOP" + "#" + "&& (reload_completed + || (!reg_mentioned_p (operands[0], operands[1]) + && !reg_mentioned_p (operands[0], operands[2])))" + [(set (match_dup 0) + (match_dup 3)) + (set (match_dup 0) + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 2) + (parallel [(const_int 1) + (const_int 3)])))) + (match_dup 0)))] +{ + operands[3] = CONST0_RTX (V2DImode); +} + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn "xop_pmacsdqh" + [(set (match_operand:V2DI 0 "register_operand" "=x,x,x") + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 0) + (const_int 2)])))) + (match_operand:V2DI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacsdqh\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsdqh\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsdqh\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn_and_split "*xop_pmacsdqh_mem" + [(set (match_operand:V2DI 0 "register_operand" "=&x,&x,&x") + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 0) + (const_int 2)])))) + (match_operand:V2DI 3 "memory_operand" "m,m,m")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, -1, true)" + "#" + "&& (reload_completed + || (!reg_mentioned_p (operands[0], operands[1]) + && !reg_mentioned_p (operands[0], operands[2])))" + [(set (match_dup 0) + (match_dup 3)) + (set (match_dup 0) + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 1) + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 2) + (parallel [(const_int 0) + (const_int 2)])))) + (match_dup 0)))]) + +;; We don't have a straight 32-bit parallel multiply and extend on XOP, so +;; fake it with a multiply/add. In general, we expect the define_split to +;; occur before register allocation, so we have to handle the corner case where +;; the target is the same as either operands[1] or operands[2] +(define_insn_and_split "xop_mulv2div2di3_high" + [(set (match_operand:V2DI 0 "register_operand" "=&x") + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "%x") + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 2 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2)])))))] + "TARGET_XOP" + "#" + "&& (reload_completed + || (!reg_mentioned_p (operands[0], operands[1]) + && !reg_mentioned_p (operands[0], operands[2])))" + [(set (match_dup 0) + (match_dup 3)) + (set (match_dup 0) + (plus:V2DI + (mult:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 1) + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 2) + (parallel [(const_int 0) + (const_int 2)])))) + (match_dup 0)))] +{ + operands[3] = CONST0_RTX (V2DImode); +} + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +;; XOP parallel integer multiply/add instructions for the intrinisics +(define_insn "xop_pmacsswd" + [(set (match_operand:V4SI 0 "register_operand" "=x,x,x") + (ss_plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)])))) + (match_operand:V4SI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacsswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacsswd\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn "xop_pmacswd" + [(set (match_operand:V4SI 0 "register_operand" "=x,x,x") + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)])))) + (match_operand:V4SI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmacswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmacswd\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn "xop_pmadcsswd" + [(set (match_operand:V4SI 0 "register_operand" "=x,x,x") + (ss_plus:V4SI + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)])))) + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_dup 2) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))))) + (match_operand:V4SI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmadcsswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmadcsswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmadcsswd\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +(define_insn "xop_pmadcswd" + [(set (match_operand:V4SI 0 "register_operand" "=x,x,x") + (plus:V4SI + (plus:V4SI + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand" "%x,x,m") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 2 "nonimmediate_operand" "x,m,x") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)])))) + (mult:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_dup 2) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)]))))) + (match_operand:V4SI 3 "register_operand" "x,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, false, 1, true)" + "@ + vpmadcswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmadcswd\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpmadcswd\t{%3, %1, %2, %0|%0, %2, %1, %3}" + [(set_attr "type" "ssemuladd") + (set_attr "mode" "TI")]) + +;; XOP parallel XMM conditional moves +(define_insn "xop_pcmov_" + [(set (match_operand:SSEMODE 0 "register_operand" "=x,x,x") + (if_then_else:SSEMODE + (match_operand:SSEMODE 3 "nonimmediate_operand" "x,x,xm") + (match_operand:SSEMODE 1 "vector_move_operand" "x,xm,x") + (match_operand:SSEMODE 2 "vector_move_operand" "xm,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, true, 1, false)" + "@ + vpcmov\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpcmov\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpcmov\t{%3, %2, %1, %0|%0, %1, %2, %3}" + [(set_attr "type" "sse4arg")]) + +(define_insn "xop_pcmov_256" + [(set (match_operand:AVX256MODE 0 "register_operand" "=x,x,x") + (if_then_else:AVX256MODE + (match_operand:AVX256MODE 3 "nonimmediate_operand" "x,x,xm") + (match_operand:AVX256MODE 1 "vector_move_operand" "x,xm,x") + (match_operand:AVX256MODE 2 "vector_move_operand" "xm,x,x")))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, true, 1, false)" + "@ + vpcmov\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpcmov\t{%3, %2, %1, %0|%0, %1, %2, %3} + vpcmov\t{%3, %2, %1, %0|%0, %1, %2, %3}" + [(set_attr "type" "sse4arg")]) + +;; XOP horizontal add/subtract instructions +(define_insn "xop_phaddbw" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (plus:V8HI + (sign_extend:V8HI + (vec_select:V8QI + (match_operand:V16QI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6) + (const_int 8) + (const_int 10) + (const_int 12) + (const_int 14)]))) + (sign_extend:V8HI + (vec_select:V8QI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7) + (const_int 9) + (const_int 11) + (const_int 13) + (const_int 15)])))))] + "TARGET_XOP" + "vphaddbw\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddbd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (plus:V4SI + (plus:V4SI + (sign_extend:V4SI + (vec_select:V4QI + (match_operand:V16QI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 4) + (const_int 8) + (const_int 12)]))) + (sign_extend:V4SI + (vec_select:V4QI + (match_dup 1) + (parallel [(const_int 1) + (const_int 5) + (const_int 9) + (const_int 13)])))) + (plus:V4SI + (sign_extend:V4SI + (vec_select:V4QI + (match_dup 1) + (parallel [(const_int 2) + (const_int 6) + (const_int 10) + (const_int 14)]))) + (sign_extend:V4SI + (vec_select:V4QI + (match_dup 1) + (parallel [(const_int 3) + (const_int 7) + (const_int 11) + (const_int 15)]))))))] + "TARGET_XOP" + "vphaddbd\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddbq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (plus:V2DI + (plus:V2DI + (plus:V2DI + (sign_extend:V2DI + (vec_select:V2QI + (match_operand:V16QI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 4)]))) + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 1) + (const_int 5)])))) + (plus:V2DI + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 2) + (const_int 6)]))) + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 3) + (const_int 7)]))))) + (plus:V2DI + (plus:V2DI + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 8) + (const_int 12)]))) + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 9) + (const_int 13)])))) + (plus:V2DI + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 10) + (const_int 14)]))) + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 11) + (const_int 15)])))))))] + "TARGET_XOP" + "vphaddbq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddwd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (plus:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)])))))] + "TARGET_XOP" + "vphaddwd\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddwq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (plus:V2DI + (plus:V2DI + (sign_extend:V2DI + (vec_select:V2HI + (match_operand:V8HI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 4)]))) + (sign_extend:V2DI + (vec_select:V2HI + (match_dup 1) + (parallel [(const_int 1) + (const_int 5)])))) + (plus:V2DI + (sign_extend:V2DI + (vec_select:V2HI + (match_dup 1) + (parallel [(const_int 2) + (const_int 6)]))) + (sign_extend:V2DI + (vec_select:V2HI + (match_dup 1) + (parallel [(const_int 3) + (const_int 7)]))))))] + "TARGET_XOP" + "vphaddwq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phadddq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (plus:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3)])))))] + "TARGET_XOP" + "vphadddq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddubw" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (plus:V8HI + (zero_extend:V8HI + (vec_select:V8QI + (match_operand:V16QI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6) + (const_int 8) + (const_int 10) + (const_int 12) + (const_int 14)]))) + (zero_extend:V8HI + (vec_select:V8QI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7) + (const_int 9) + (const_int 11) + (const_int 13) + (const_int 15)])))))] + "TARGET_XOP" + "vphaddubw\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddubd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (plus:V4SI + (plus:V4SI + (zero_extend:V4SI + (vec_select:V4QI + (match_operand:V16QI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 4) + (const_int 8) + (const_int 12)]))) + (zero_extend:V4SI + (vec_select:V4QI + (match_dup 1) + (parallel [(const_int 1) + (const_int 5) + (const_int 9) + (const_int 13)])))) + (plus:V4SI + (zero_extend:V4SI + (vec_select:V4QI + (match_dup 1) + (parallel [(const_int 2) + (const_int 6) + (const_int 10) + (const_int 14)]))) + (zero_extend:V4SI + (vec_select:V4QI + (match_dup 1) + (parallel [(const_int 3) + (const_int 7) + (const_int 11) + (const_int 15)]))))))] + "TARGET_XOP" + "vphaddubd\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddubq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (plus:V2DI + (plus:V2DI + (plus:V2DI + (zero_extend:V2DI + (vec_select:V2QI + (match_operand:V16QI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 4)]))) + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 1) + (const_int 5)])))) + (plus:V2DI + (zero_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 2) + (const_int 6)]))) + (zero_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 3) + (const_int 7)]))))) + (plus:V2DI + (plus:V2DI + (zero_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 8) + (const_int 12)]))) + (sign_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 9) + (const_int 13)])))) + (plus:V2DI + (zero_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 10) + (const_int 14)]))) + (zero_extend:V2DI + (vec_select:V2QI + (match_dup 1) + (parallel [(const_int 11) + (const_int 15)])))))))] + "TARGET_XOP" + "vphaddubq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phadduwd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (plus:V4SI + (zero_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)]))) + (zero_extend:V4SI + (vec_select:V4HI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)])))))] + "TARGET_XOP" + "vphadduwd\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phadduwq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (plus:V2DI + (plus:V2DI + (zero_extend:V2DI + (vec_select:V2HI + (match_operand:V8HI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 4)]))) + (zero_extend:V2DI + (vec_select:V2HI + (match_dup 1) + (parallel [(const_int 1) + (const_int 5)])))) + (plus:V2DI + (zero_extend:V2DI + (vec_select:V2HI + (match_dup 1) + (parallel [(const_int 2) + (const_int 6)]))) + (zero_extend:V2DI + (vec_select:V2HI + (match_dup 1) + (parallel [(const_int 3) + (const_int 7)]))))))] + "TARGET_XOP" + "vphadduwq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phaddudq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (plus:V2DI + (zero_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2)]))) + (zero_extend:V2DI + (vec_select:V2SI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3)])))))] + "TARGET_XOP" + "vphaddudq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phsubbw" + [(set (match_operand:V8HI 0 "register_operand" "=x") + (minus:V8HI + (sign_extend:V8HI + (vec_select:V8QI + (match_operand:V16QI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6) + (const_int 8) + (const_int 10) + (const_int 12) + (const_int 14)]))) + (sign_extend:V8HI + (vec_select:V8QI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7) + (const_int 9) + (const_int 11) + (const_int 13) + (const_int 15)])))))] + "TARGET_XOP" + "vphsubbw\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phsubwd" + [(set (match_operand:V4SI 0 "register_operand" "=x") + (minus:V4SI + (sign_extend:V4SI + (vec_select:V4HI + (match_operand:V8HI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2) + (const_int 4) + (const_int 6)]))) + (sign_extend:V4SI + (vec_select:V4HI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3) + (const_int 5) + (const_int 7)])))))] + "TARGET_XOP" + "vphsubwd\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +(define_insn "xop_phsubdq" + [(set (match_operand:V2DI 0 "register_operand" "=x") + (minus:V2DI + (sign_extend:V2DI + (vec_select:V2SI + (match_operand:V4SI 1 "nonimmediate_operand" "xm") + (parallel [(const_int 0) + (const_int 2)]))) + (sign_extend:V2DI + (vec_select:V2SI + (match_dup 1) + (parallel [(const_int 1) + (const_int 3)])))))] + "TARGET_XOP" + "vphsubdq\t{%1, %0|%0, %1}" + [(set_attr "type" "sseiadd1")]) + +;; XOP permute instructions +(define_insn "xop_pperm" + [(set (match_operand:V16QI 0 "register_operand" "=x,x,x") + (unspec:V16QI + [(match_operand:V16QI 1 "nonimmediate_operand" "x,x,xm") + (match_operand:V16QI 2 "nonimmediate_operand" "x,xm,x") + (match_operand:V16QI 3 "nonimmediate_operand" "xm,x,x")] + UNSPEC_XOP_PERMUTE))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, true, 1, false)" + "vpperm\t{%3, %2, %1, %0|%0, %1, %2, %3}" + [(set_attr "type" "sse4arg") + (set_attr "mode" "TI")]) + +;; XOP pack instructions that combine two vectors into a smaller vector +(define_insn "xop_pperm_pack_v2di_v4si" + [(set (match_operand:V4SI 0 "register_operand" "=x,x,x") + (vec_concat:V4SI + (truncate:V2SI + (match_operand:V2DI 1 "nonimmediate_operand" "x,x,xm")) + (truncate:V2SI + (match_operand:V2DI 2 "nonimmediate_operand" "x,xm,x")))) + (use (match_operand:V16QI 3 "nonimmediate_operand" "xm,x,x"))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, true, 1, false)" + "vpperm\t{%3, %2, %1, %0|%0, %1, %2, %3}" + [(set_attr "type" "sse4arg") + (set_attr "mode" "TI")]) + +(define_insn "xop_pperm_pack_v4si_v8hi" + [(set (match_operand:V8HI 0 "register_operand" "=x,x,x") + (vec_concat:V8HI + (truncate:V4HI + (match_operand:V4SI 1 "nonimmediate_operand" "x,x,xm")) + (truncate:V4HI + (match_operand:V4SI 2 "nonimmediate_operand" "x,xm,x")))) + (use (match_operand:V16QI 3 "nonimmediate_operand" "xm,x,x"))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, true, 1, false)" + "vpperm\t{%3, %2, %1, %0|%0, %1, %2, %3}" + [(set_attr "type" "sse4arg") + (set_attr "mode" "TI")]) + +(define_insn "xop_pperm_pack_v8hi_v16qi" + [(set (match_operand:V16QI 0 "register_operand" "=x,x,x") + (vec_concat:V16QI + (truncate:V8QI + (match_operand:V8HI 1 "nonimmediate_operand" "x,x,xm")) + (truncate:V8QI + (match_operand:V8HI 2 "nonimmediate_operand" "x,xm,x")))) + (use (match_operand:V16QI 3 "nonimmediate_operand" "xm,x,x"))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 4, true, 1, false)" + "vpperm\t{%3, %2, %1, %0|%0, %1, %2, %3}" + [(set_attr "type" "sse4arg") + (set_attr "mode" "TI")]) + +;; XOP packed rotate instructions +(define_expand "rotl3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "") + (rotate:SSEMODE1248 + (match_operand:SSEMODE1248 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand")))] + "TARGET_XOP" +{ + /* If we were given a scalar, convert it to parallel */ + if (! const_0_to__operand (operands[2], SImode)) + { + rtvec vs = rtvec_alloc (); + rtx par = gen_rtx_PARALLEL (mode, vs); + rtx reg = gen_reg_rtx (mode); + rtx op2 = operands[2]; + int i; + + if (GET_MODE (op2) != mode) + { + op2 = gen_reg_rtx (mode); + convert_move (op2, operands[2], false); + } + + for (i = 0; i < ; i++) + RTVEC_ELT (vs, i) = op2; + + emit_insn (gen_vec_init (reg, par)); + emit_insn (gen_xop_vrotl3 (operands[0], operands[1], reg)); + DONE; + } +}) + +(define_expand "rotr3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "") + (rotatert:SSEMODE1248 + (match_operand:SSEMODE1248 1 "nonimmediate_operand" "") + (match_operand:SI 2 "general_operand")))] + "TARGET_XOP" +{ + /* If we were given a scalar, convert it to parallel */ + if (! const_0_to__operand (operands[2], SImode)) + { + rtvec vs = rtvec_alloc (); + rtx par = gen_rtx_PARALLEL (mode, vs); + rtx neg = gen_reg_rtx (mode); + rtx reg = gen_reg_rtx (mode); + rtx op2 = operands[2]; + int i; + + if (GET_MODE (op2) != mode) + { + op2 = gen_reg_rtx (mode); + convert_move (op2, operands[2], false); + } + + for (i = 0; i < ; i++) + RTVEC_ELT (vs, i) = op2; + + emit_insn (gen_vec_init (reg, par)); + emit_insn (gen_neg2 (neg, reg)); + emit_insn (gen_xop_vrotl3 (operands[0], operands[1], neg)); + DONE; + } +}) + +(define_insn "xop_rotl3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x") + (rotate:SSEMODE1248 + (match_operand:SSEMODE1248 1 "nonimmediate_operand" "xm") + (match_operand:SI 2 "const_0_to__operand" "n")))] + "TARGET_XOP" + "vprot\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "sseishft") + (set_attr "length_immediate" "1") + (set_attr "mode" "TI")]) + +(define_insn "xop_rotr3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x") + (rotatert:SSEMODE1248 + (match_operand:SSEMODE1248 1 "nonimmediate_operand" "xm") + (match_operand:SI 2 "const_0_to__operand" "n")))] + "TARGET_XOP" +{ + operands[3] = GEN_INT (( * 8) - INTVAL (operands[2])); + return \"vprot\t{%3, %1, %0|%0, %1, %3}\"; +} + [(set_attr "type" "sseishft") + (set_attr "length_immediate" "1") + (set_attr "mode" "TI")]) + +(define_expand "vrotr3" + [(match_operand:SSEMODE1248 0 "register_operand" "") + (match_operand:SSEMODE1248 1 "register_operand" "") + (match_operand:SSEMODE1248 2 "register_operand" "")] + "TARGET_XOP" +{ + rtx reg = gen_reg_rtx (mode); + emit_insn (gen_neg2 (reg, operands[2])); + emit_insn (gen_xop_vrotl3 (operands[0], operands[1], reg)); + DONE; +}) + +(define_expand "vrotl3" + [(match_operand:SSEMODE1248 0 "register_operand" "") + (match_operand:SSEMODE1248 1 "register_operand" "") + (match_operand:SSEMODE1248 2 "register_operand" "")] + "TARGET_XOP" +{ + emit_insn (gen_xop_vrotl3 (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_insn "xop_vrotl3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x,x") + (if_then_else:SSEMODE1248 + (ge:SSEMODE1248 + (match_operand:SSEMODE1248 2 "nonimmediate_operand" "xm,x") + (const_int 0)) + (rotate:SSEMODE1248 + (match_operand:SSEMODE1248 1 "nonimmediate_operand" "x,xm") + (match_dup 2)) + (rotatert:SSEMODE1248 + (match_dup 1) + (neg:SSEMODE1248 (match_dup 2)))))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 3, true, 1, false)" + "vprot\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "sseishft") + (set_attr "prefix_data16" "0") + (set_attr "prefix_extra" "2") + (set_attr "mode" "TI")]) + +;; XOP packed shift instructions. +;; FIXME: add V2DI back in +(define_expand "vlshr3" + [(match_operand:SSEMODE124 0 "register_operand" "") + (match_operand:SSEMODE124 1 "register_operand" "") + (match_operand:SSEMODE124 2 "register_operand" "")] + "TARGET_XOP" +{ + rtx neg = gen_reg_rtx (mode); + emit_insn (gen_neg2 (neg, operands[2])); + emit_insn (gen_xop_lshl3 (operands[0], operands[1], neg)); + DONE; +}) + +(define_expand "vashr3" + [(match_operand:SSEMODE124 0 "register_operand" "") + (match_operand:SSEMODE124 1 "register_operand" "") + (match_operand:SSEMODE124 2 "register_operand" "")] + "TARGET_XOP" +{ + rtx neg = gen_reg_rtx (mode); + emit_insn (gen_neg2 (neg, operands[2])); + emit_insn (gen_xop_ashl3 (operands[0], operands[1], neg)); + DONE; +}) + +(define_expand "vashl3" + [(match_operand:SSEMODE124 0 "register_operand" "") + (match_operand:SSEMODE124 1 "register_operand" "") + (match_operand:SSEMODE124 2 "register_operand" "")] + "TARGET_XOP" +{ + emit_insn (gen_xop_ashl3 (operands[0], operands[1], operands[2])); + DONE; +}) + +(define_insn "xop_ashl3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x,x") + (if_then_else:SSEMODE1248 + (ge:SSEMODE1248 + (match_operand:SSEMODE1248 2 "nonimmediate_operand" "xm,x") + (const_int 0)) + (ashift:SSEMODE1248 + (match_operand:SSEMODE1248 1 "nonimmediate_operand" "x,xm") + (match_dup 2)) + (ashiftrt:SSEMODE1248 + (match_dup 1) + (neg:SSEMODE1248 (match_dup 2)))))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 3, true, 1, false)" + "vpsha\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "sseishft") + (set_attr "prefix_data16" "0") + (set_attr "prefix_extra" "2") + (set_attr "mode" "TI")]) + +(define_insn "xop_lshl3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x,x") + (if_then_else:SSEMODE1248 + (ge:SSEMODE1248 + (match_operand:SSEMODE1248 2 "nonimmediate_operand" "xm,x") + (const_int 0)) + (ashift:SSEMODE1248 + (match_operand:SSEMODE1248 1 "nonimmediate_operand" "x,xm") + (match_dup 2)) + (lshiftrt:SSEMODE1248 + (match_dup 1) + (neg:SSEMODE1248 (match_dup 2)))))] + "TARGET_XOP && ix86_fma4_valid_op_p (operands, insn, 3, true, 1, false)" + "vpshl\t{%2, %1, %0|%0, %1, %2}" + [(set_attr "type" "sseishft") + (set_attr "prefix_data16" "0") + (set_attr "prefix_extra" "2") + (set_attr "mode" "TI")]) + +;; SSE2 doesn't have some shift varients, so define versions for XOP +(define_expand "ashlv16qi3" + [(match_operand:V16QI 0 "register_operand" "") + (match_operand:V16QI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")] + "TARGET_XOP" +{ + rtvec vs = rtvec_alloc (16); + rtx par = gen_rtx_PARALLEL (V16QImode, vs); + rtx reg = gen_reg_rtx (V16QImode); + int i; + for (i = 0; i < 16; i++) + RTVEC_ELT (vs, i) = operands[2]; + + emit_insn (gen_vec_initv16qi (reg, par)); + emit_insn (gen_xop_ashlv16qi3 (operands[0], operands[1], reg)); + DONE; +}) + +(define_expand "lshlv16qi3" + [(match_operand:V16QI 0 "register_operand" "") + (match_operand:V16QI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")] + "TARGET_XOP" +{ + rtvec vs = rtvec_alloc (16); + rtx par = gen_rtx_PARALLEL (V16QImode, vs); + rtx reg = gen_reg_rtx (V16QImode); + int i; + for (i = 0; i < 16; i++) + RTVEC_ELT (vs, i) = operands[2]; + + emit_insn (gen_vec_initv16qi (reg, par)); + emit_insn (gen_xop_lshlv16qi3 (operands[0], operands[1], reg)); + DONE; +}) + +(define_expand "ashrv16qi3" + [(match_operand:V16QI 0 "register_operand" "") + (match_operand:V16QI 1 "register_operand" "") + (match_operand:SI 2 "nonmemory_operand" "")] + "TARGET_XOP" +{ + rtvec vs = rtvec_alloc (16); + rtx par = gen_rtx_PARALLEL (V16QImode, vs); + rtx reg = gen_reg_rtx (V16QImode); + int i; + rtx ele = ((CONST_INT_P (operands[2])) + ? GEN_INT (- INTVAL (operands[2])) + : operands[2]); + + for (i = 0; i < 16; i++) + RTVEC_ELT (vs, i) = ele; + + emit_insn (gen_vec_initv16qi (reg, par)); + + if (!CONST_INT_P (operands[2])) + { + rtx neg = gen_reg_rtx (V16QImode); + emit_insn (gen_negv16qi2 (neg, reg)); + emit_insn (gen_xop_ashlv16qi3 (operands[0], operands[1], neg)); + } + else + emit_insn (gen_xop_ashlv16qi3 (operands[0], operands[1], reg)); + + DONE; +}) + +(define_expand "ashrv2di3" + [(match_operand:V2DI 0 "register_operand" "") + (match_operand:V2DI 1 "register_operand" "") + (match_operand:DI 2 "nonmemory_operand" "")] + "TARGET_XOP" +{ + rtvec vs = rtvec_alloc (2); + rtx par = gen_rtx_PARALLEL (V2DImode, vs); + rtx reg = gen_reg_rtx (V2DImode); + rtx ele; + + if (CONST_INT_P (operands[2])) + ele = GEN_INT (- INTVAL (operands[2])); + else if (GET_MODE (operands[2]) != DImode) + { + rtx move = gen_reg_rtx (DImode); + ele = gen_reg_rtx (DImode); + convert_move (move, operands[2], false); + emit_insn (gen_negdi2 (ele, move)); + } + else + { + ele = gen_reg_rtx (DImode); + emit_insn (gen_negdi2 (ele, operands[2])); + } + + RTVEC_ELT (vs, 0) = ele; + RTVEC_ELT (vs, 1) = ele; + emit_insn (gen_vec_initv2di (reg, par)); + emit_insn (gen_xop_ashlv2di3 (operands[0], operands[1], reg)); + DONE; +}) + +;; XOP FRCZ support +;; parallel insns +(define_insn "xop_frcz2" + [(set (match_operand:SSEMODEF2P 0 "register_operand" "=x") + (unspec:SSEMODEF2P + [(match_operand:SSEMODEF2P 1 "nonimmediate_operand" "xm")] + UNSPEC_FRCZ))] + "TARGET_XOP" + "vfrcz\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt1") + (set_attr "mode" "")]) + +;; scalar insns +(define_insn "xop_vmfrcz2" + [(set (match_operand:SSEMODEF2P 0 "register_operand" "=x") + (vec_merge:SSEMODEF2P + (unspec:SSEMODEF2P + [(match_operand:SSEMODEF2P 2 "nonimmediate_operand" "xm")] + UNSPEC_FRCZ) + (match_operand:SSEMODEF2P 1 "register_operand" "0") + (const_int 1)))] + "TARGET_XOP" + "vfrcz\t{%2, %0|%0, %2}" + [(set_attr "type" "ssecvt1") + (set_attr "mode" "")]) + +(define_insn "xop_frcz2256" + [(set (match_operand:FMA4MODEF4 0 "register_operand" "=x") + (unspec:FMA4MODEF4 + [(match_operand:FMA4MODEF4 1 "nonimmediate_operand" "xm")] + UNSPEC_FRCZ))] + "TARGET_XOP" + "vfrcz\t{%1, %0|%0, %1}" + [(set_attr "type" "ssecvt1") + (set_attr "mode" "")]) + +(define_insn "xop_maskcmp3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x") + (match_operator:SSEMODE1248 1 "ix86_comparison_int_operator" + [(match_operand:SSEMODE1248 2 "register_operand" "x") + (match_operand:SSEMODE1248 3 "nonimmediate_operand" "xm")]))] + "TARGET_XOP" + "vpcom%Y1\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "sse4arg") + (set_attr "prefix_data16" "0") + (set_attr "prefix_rep" "0") + (set_attr "prefix_extra" "2") + (set_attr "length_immediate" "1") + (set_attr "mode" "TI")]) + +(define_insn "xop_maskcmp_uns3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x") + (match_operator:SSEMODE1248 1 "ix86_comparison_uns_operator" + [(match_operand:SSEMODE1248 2 "register_operand" "x") + (match_operand:SSEMODE1248 3 "nonimmediate_operand" "xm")]))] + "TARGET_XOP" + "vpcom%Y1u\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "ssecmp") + (set_attr "prefix_data16" "0") + (set_attr "prefix_rep" "0") + (set_attr "prefix_extra" "2") + (set_attr "length_immediate" "1") + (set_attr "mode" "TI")]) + +;; Version of pcom*u* that is called from the intrinsics that allows pcomequ* +;; and pcomneu* not to be converted to the signed ones in case somebody needs +;; the exact instruction generated for the intrinsic. +(define_insn "xop_maskcmp_uns23" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x") + (unspec:SSEMODE1248 + [(match_operator:SSEMODE1248 1 "ix86_comparison_uns_operator" + [(match_operand:SSEMODE1248 2 "register_operand" "x") + (match_operand:SSEMODE1248 3 "nonimmediate_operand" "xm")])] + UNSPEC_XOP_UNSIGNED_CMP))] + "TARGET_XOP" + "vpcom%Y1u\t{%3, %2, %0|%0, %2, %3}" + [(set_attr "type" "ssecmp") + (set_attr "prefix_data16" "0") + (set_attr "prefix_extra" "2") + (set_attr "length_immediate" "1") + (set_attr "mode" "TI")]) + +;; Pcomtrue and pcomfalse support. These are useless instructions, but are +;; being added here to be complete. +(define_insn "xop_pcom_tf3" + [(set (match_operand:SSEMODE1248 0 "register_operand" "=x") + (unspec:SSEMODE1248 + [(match_operand:SSEMODE1248 1 "register_operand" "x") + (match_operand:SSEMODE1248 2 "nonimmediate_operand" "xm") + (match_operand:SI 3 "const_int_operand" "n")] + UNSPEC_XOP_TRUEFALSE))] + "TARGET_XOP" +{ + return ((INTVAL (operands[3]) != 0) + ? "vpcomtrue\t{%2, %1, %0|%0, %1, %2}" + : "vpcomfalse\t{%2, %1, %0|%0, %1, %2}"); +} + [(set_attr "type" "ssecmp") + (set_attr "prefix_data16" "0") + (set_attr "prefix_extra" "2") + (set_attr "length_immediate" "1") + (set_attr "mode" "TI")]) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define_insn "*avx_aesenc" [(set (match_operand:V2DI 0 "register_operand" "=x") (unspec:V2DI [(match_operand:V2DI 1 "register_operand" "x") diff --git a/gcc/config/i386/winnt-cxx.c b/gcc/config/i386/winnt-cxx.c index 9df7cf645bb..48518adc765 100644 --- a/gcc/config/i386/winnt-cxx.c +++ b/gcc/config/i386/winnt-cxx.c @@ -1,7 +1,6 @@ /* Target support for C++ classes on Windows. Contributed by Danny Smith (dannysmith@users.sourceforge.net) - Copyright (C) 2005, 2007 - Free Software Foundation, Inc. + Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc. This file is part of GCC. @@ -28,7 +27,7 @@ along with GCC; see the file COPYING3. If not see #include "hard-reg-set.h" #include "output.h" #include "tree.h" -#include "cp/cp-tree.h" /* this is why we're a separate module */ +#include "cp/cp-tree.h" /* This is why we're a separate module. */ #include "flags.h" #include "tm_p.h" #include "toplev.h" @@ -52,49 +51,44 @@ i386_pe_type_dllimport_p (tree decl) || DECL_TEMPLATE_INSTANTIATION (decl) || DECL_ARTIFICIAL (decl))) return false; - - - /* Don't mark defined functions as dllimport. This code will only be - reached if we see a non-inline function defined out-of-class. */ - else if (TREE_CODE (decl) == FUNCTION_DECL - && (DECL_INITIAL (decl))) - return false; - - /* Don't allow definitions of static data members in dllimport class, - If vtable data is marked as DECL_EXTERNAL, import it; otherwise just - ignore the class attribute. */ - else if (TREE_CODE (decl) == VAR_DECL - && TREE_STATIC (decl) && TREE_PUBLIC (decl) - && !DECL_EXTERNAL (decl)) - { - if (!DECL_VIRTUAL_P (decl)) - error ("definition of static data member %q+D of " - "dllimport'd class", decl); - return false; - } - + + /* Overrides of the class dllimport decls by out-of-class definitions are + handled by tree.c:merge_dllimport_decl_attributes. */ return true; } - bool i386_pe_type_dllexport_p (tree decl) { - gcc_assert (TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == FUNCTION_DECL); - /* Avoid exporting compiler-generated default dtors and copy ctors. - The only artificial methods that need to be exported are virtual - and non-virtual thunks. */ - if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE - && DECL_ARTIFICIAL (decl) && !DECL_THUNK_P (decl)) - return false; - return true; + gcc_assert (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL); + + /* Avoid exporting compiler-generated default dtors and copy ctors. + The only artificial methods that need to be exported are virtual + and non-virtual thunks. */ + if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE + && DECL_ARTIFICIAL (decl) && !DECL_THUNK_P (decl)) + return false; + return true; } static inline void maybe_add_dllimport (tree decl) { if (i386_pe_type_dllimport_p (decl)) - DECL_DLLIMPORT_P (decl) = 1; + DECL_DLLIMPORT_P (decl) = 1; +} + +static inline void maybe_add_dllexport (tree decl) +{ + if (i386_pe_type_dllexport_p (decl)) + { + tree decl_attrs = DECL_ATTRIBUTES (decl); + if (lookup_attribute ("dllexport", decl_attrs) != NULL_TREE) + /* Already done. */ + return; + DECL_ATTRIBUTES (decl) = tree_cons (get_identifier ("dllexport"), + NULL_TREE, decl_attrs); + } } void @@ -103,41 +97,69 @@ i386_pe_adjust_class_at_definition (tree t) tree member; gcc_assert (CLASS_TYPE_P (t)); + + + if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (t)) != NULL_TREE) + { + /* Check static VAR_DECL's. */ + for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member)) + if (TREE_CODE (member) == VAR_DECL) + maybe_add_dllexport (member); + + /* Check FUNCTION_DECL's. */ + for (member = TYPE_METHODS (t); member; member = TREE_CHAIN (member)) + if (TREE_CODE (member) == FUNCTION_DECL) + { + tree thunk; + maybe_add_dllexport (member); + + /* Also add the attribute to its thunks. */ + for (thunk = DECL_THUNKS (member); thunk; + thunk = TREE_CHAIN (thunk)) + maybe_add_dllexport (thunk); + } + /* Check vtables */ + for (member = CLASSTYPE_VTABLES (t); member; member = TREE_CHAIN (member)) + if (TREE_CODE (member) == VAR_DECL) + maybe_add_dllexport (member); + } - /* We only look at dllimport. The only thing that dllexport does is - add stuff to a '.drectiv' section at end-of-file, so no need to do - anything for dllexport'd classes until we generate RTL. */ - if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (t)) == NULL_TREE) - return; - - /* We don't actually add the attribute to the decl, just set the flag - that signals that the address of this symbol is not a compile-time - constant. Any subsequent out-of-class declaration of members wil - cause the DECL_DLLIMPORT_P flag to be unset. - (See tree.c: merge_dllimport_decl_attributes). - That is just right since out-of class declarations can only be a - definition. We recheck the class members at RTL generation to - emit warnings if this has happened. Definition of static data member - of dllimport'd class always causes an error (as per MS compiler). - */ - - /* Check static VAR_DECL's. */ - for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member)) - if (TREE_CODE (member) == VAR_DECL) - maybe_add_dllimport (member); + else if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (t)) != NULL_TREE) + { + /* We don't actually add the attribute to the decl, just set the flag + that signals that the address of this symbol is not a compile-time + constant. Any subsequent out-of-class declaration of members wil + cause the DECL_DLLIMPORT_P flag to be unset. + (See tree.c: merge_dllimport_decl_attributes). + That is just right since out-of class declarations can only be a + definition. */ + + /* Check static VAR_DECL's. */ + for (member = TYPE_FIELDS (t); member; member = TREE_CHAIN (member)) + if (TREE_CODE (member) == VAR_DECL) + maybe_add_dllimport (member); - /* Check FUNCTION_DECL's. */ - for (member = TYPE_METHODS (t); member; member = TREE_CHAIN (member)) - if (TREE_CODE (member) == FUNCTION_DECL) - maybe_add_dllimport (member); + /* Check FUNCTION_DECL's. */ + for (member = TYPE_METHODS (t); member; member = TREE_CHAIN (member)) + if (TREE_CODE (member) == FUNCTION_DECL) + { + tree thunk; + maybe_add_dllimport (member); + + /* Also add the attribute to its thunks. */ + for (thunk = DECL_THUNKS (member); thunk; + thunk = TREE_CHAIN (thunk)) + maybe_add_dllimport (thunk); + } - /* Check vtables */ - for (member = CLASSTYPE_VTABLES (t); member; member = TREE_CHAIN (member)) - if (TREE_CODE (member) == VAR_DECL) - maybe_add_dllimport (member); - -/* We leave typeinfo tables alone. We can't mark TI objects as - dllimport, since the address of a secondary VTT may be needed - for static initialization of a primary VTT. VTT's of - dllimport'd classes should always be link-once COMDAT. */ + /* Check vtables */ + for (member = CLASSTYPE_VTABLES (t); member; member = TREE_CHAIN (member)) + if (TREE_CODE (member) == VAR_DECL) + maybe_add_dllimport (member); + + /* We leave typeinfo tables alone. We can't mark TI objects as + dllimport, since the address of a secondary VTT may be needed + for static initialization of a primary VTT. VTT's of + dllimport'd classes should always be link-once COMDAT. */ + } } diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c index 7069c40846f..f8dcaa9673a 100644 --- a/gcc/config/i386/winnt.c +++ b/gcc/config/i386/winnt.c @@ -102,8 +102,6 @@ associated_type (tree decl) static bool i386_pe_determine_dllexport_p (tree decl) { - tree assoc; - if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return false; @@ -114,11 +112,6 @@ i386_pe_determine_dllexport_p (tree decl) if (lookup_attribute ("dllexport", DECL_ATTRIBUTES (decl))) return true; - /* Also mark class members of exported classes with dllexport. */ - assoc = associated_type (decl); - if (assoc && lookup_attribute ("dllexport", TYPE_ATTRIBUTES (assoc))) - return i386_pe_type_dllexport_p (decl); - return false; } @@ -132,18 +125,23 @@ i386_pe_determine_dllimport_p (tree decl) if (TREE_CODE (decl) != VAR_DECL && TREE_CODE (decl) != FUNCTION_DECL) return false; - /* Lookup the attribute in addition to checking the DECL_DLLIMPORT_P flag. - We may need to override an earlier decision. */ if (DECL_DLLIMPORT_P (decl)) return true; /* The DECL_DLLIMPORT_P flag was set for decls in the class definition by targetm.cxx.adjust_class_at_definition. Check again to emit - warnings if the class attribute has been overridden by an - out-of-class definition. */ + error message if the class attribute has been overridden by an + out-of-class definition of static data. */ assoc = associated_type (decl); - if (assoc && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (assoc))) - return i386_pe_type_dllimport_p (decl); + if (assoc && lookup_attribute ("dllimport", TYPE_ATTRIBUTES (assoc)) + && TREE_CODE (decl) == VAR_DECL + && TREE_STATIC (decl) && TREE_PUBLIC (decl) + && !DECL_EXTERNAL (decl) + /* vtable's are linkonce constants, so defining a vtable is not + an error as long as we don't try to import it too. */ + && !DECL_VIRTUAL_P (decl)) + error ("definition of static data member %q+D of " + "dllimport'd class", decl); return false; } @@ -308,17 +306,8 @@ i386_pe_encode_section_info (tree decl, rtx rtl, int first) if (i386_pe_determine_dllexport_p (decl)) flags |= SYMBOL_FLAG_DLLEXPORT; else if (i386_pe_determine_dllimport_p (decl)) - { - flags |= SYMBOL_FLAG_DLLIMPORT; - /* If we went through the associated_type path, this won't already - be set. Though, frankly, this seems wrong, and should be fixed - elsewhere. */ - if (!DECL_DLLIMPORT_P (decl)) - { - DECL_DLLIMPORT_P (decl) = 1; - flags &= ~SYMBOL_FLAG_LOCAL; - } - } + flags |= SYMBOL_FLAG_DLLIMPORT; + SYMBOL_REF_FLAGS (symbol) = flags; } diff --git a/gcc/config/i386/x86intrin.h b/gcc/config/i386/x86intrin.h index 7bc47f8f15d..ac7e21fd6f7 100644 --- a/gcc/config/i386/x86intrin.h +++ b/gcc/config/i386/x86intrin.h @@ -54,10 +54,6 @@ #include #endif -#ifdef __FMA4__ -#include -#endif - #if defined (__AES__) || defined (__PCLMUL__) #include #endif @@ -69,4 +65,16 @@ #include #endif +#ifdef __FMA4__ +#include +#endif + +#ifdef __XOP__ +#include +#endif + +#ifdef __LWP__ +#include +#endif + #endif /* _X86INTRIN_H_INCLUDED */ diff --git a/gcc/config/i386/xopintrin.h b/gcc/config/i386/xopintrin.h new file mode 100644 index 00000000000..803417a6a45 --- /dev/null +++ b/gcc/config/i386/xopintrin.h @@ -0,0 +1,771 @@ +/* Copyright (C) 2007, 2008, 2009 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef _X86INTRIN_H_INCLUDED +# error "Never use directly; include instead." +#endif + +#ifndef _XOPMMINTRIN_H_INCLUDED +#define _XOPMMINTRIN_H_INCLUDED + +#ifndef __XOP__ +# error "XOP instruction set not enabled" +#else + +#include + +/* Integer multiply/add intructions. */ +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maccs_epi16(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacssww ((__v8hi)__A,(__v8hi)__B, (__v8hi)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_macc_epi16(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacsww ((__v8hi)__A, (__v8hi)__B, (__v8hi)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maccsd_epi16(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacsswd ((__v8hi)__A, (__v8hi)__B, (__v4si)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maccd_epi16(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacswd ((__v8hi)__A, (__v8hi)__B, (__v4si)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maccs_epi32(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacssdd ((__v4si)__A, (__v4si)__B, (__v4si)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_macc_epi32(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacsdd ((__v4si)__A, (__v4si)__B, (__v4si)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maccslo_epi32(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacssdql ((__v4si)__A, (__v4si)__B, (__v2di)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_macclo_epi32(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacsdql ((__v4si)__A, (__v4si)__B, (__v2di)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maccshi_epi32(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacssdqh ((__v4si)__A, (__v4si)__B, (__v2di)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_macchi_epi32(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmacsdqh ((__v4si)__A, (__v4si)__B, (__v2di)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maddsd_epi16(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmadcsswd ((__v8hi)__A,(__v8hi)__B,(__v4si)__C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_maddd_epi16(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpmadcswd ((__v8hi)__A,(__v8hi)__B,(__v4si)__C); +} + +/* Packed Integer Horizontal Add and Subtract */ +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddw_epi8(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddbw ((__v16qi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddd_epi8(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddbd ((__v16qi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddq_epi8(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddbq ((__v16qi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddd_epi16(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddwd ((__v8hi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddq_epi16(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddwq ((__v8hi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddq_epi32(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphadddq ((__v4si)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddw_epu8(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddubw ((__v16qi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddd_epu8(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddubd ((__v16qi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddq_epu8(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddubq ((__v16qi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddd_epu16(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphadduwd ((__v8hi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddq_epu16(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphadduwq ((__v8hi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_haddq_epu32(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphaddudq ((__v4si)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_hsubw_epi8(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphsubbw ((__v16qi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_hsubd_epi16(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphsubwd ((__v8hi)__A); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_hsubq_epi32(__m128i __A) +{ + return (__m128i) __builtin_ia32_vphsubdq ((__v4si)__A); +} + +/* Vector conditional move and permute */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_cmov_si128(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpcmov (__A, __B, __C); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_perm_epi8(__m128i __A, __m128i __B, __m128i __C) +{ + return (__m128i) __builtin_ia32_vpperm ((__v16qi)__A, (__v16qi)__B, (__v16qi)__C); +} + +/* Packed Integer Rotates and Shifts + Rotates - Non-Immediate form */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_rot_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vprotb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_rot_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vprotw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_rot_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vprotd ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_rot_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vprotq ((__v2di)__A, (__v2di)__B); +} + +/* Rotates - Immediate form */ + +#ifdef __OPTIMIZE__ +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_roti_epi8(__m128i __A, const int __B) +{ + return (__m128i) __builtin_ia32_vprotbi ((__v16qi)__A, __B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_roti_epi16(__m128i __A, const int __B) +{ + return (__m128i) __builtin_ia32_vprotwi ((__v8hi)__A, __B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_roti_epi32(__m128i __A, const int __B) +{ + return (__m128i) __builtin_ia32_vprotdi ((__v4si)__A, __B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_roti_epi64(__m128i __A, const int __B) +{ + return (__m128i) __builtin_ia32_vprotqi ((__v2di)__A, __B); +} +#else +#define _mm_roti_epi8(A, N) \ + ((__m128i) __builtin_ia32_vprotbi ((__v16qi)(__m128i)(A), (int)(N))) +#define _mm_roti_epi16(A, N) \ + ((__m128i) __builtin_ia32_vprotwi ((__v8hi)(__m128i)(A), (int)(N))) +#define _mm_roti_epi32(A, N) \ + ((__m128i) __builtin_ia32_vprotdi ((__v4si)(__m128i)(A), (int)(N))) +#define _mm_roti_epi64(A, N) \ + ((__m128i) __builtin_ia32_vprotqi ((__v2di)(__m128i)(A), (int)(N))) +#endif + +/* Shifts */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_shl_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshlb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_shl_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshlw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_shl_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshld ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_shl_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshlq ((__v2di)__A, (__v2di)__B); +} + + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_sha_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshab ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_sha_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshaw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_sha_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshad ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_sha_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpshaq ((__v2di)__A, (__v2di)__B); +} + +/* Compare and Predicate Generation + pcom (integer, unsinged bytes) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltub ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomleub ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtub ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgeub ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomequb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomnequb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalseub ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epu8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtrueub ((__v16qi)__A, (__v16qi)__B); +} + +/*pcom (integer, unsinged words) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltuw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomleuw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtuw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgeuw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomequw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomnequw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalseuw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epu16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtrueuw ((__v8hi)__A, (__v8hi)__B); +} + +/*pcom (integer, unsinged double words) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltud ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomleud ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtud ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgeud ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomequd ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomnequd ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalseud ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epu32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtrueud ((__v4si)__A, (__v4si)__B); +} + +/*pcom (integer, unsinged quad words) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltuq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomleuq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtuq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgeuq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomequq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomnequq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalseuq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epu64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtrueuq ((__v2di)__A, (__v2di)__B); +} + +/*pcom (integer, signed bytes) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomleb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgeb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomeqb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomneqb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalseb ((__v16qi)__A, (__v16qi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epi8(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtrueb ((__v16qi)__A, (__v16qi)__B); +} + +/*pcom (integer, signed words) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomlew ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgew ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomeqw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomneqw ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalsew ((__v8hi)__A, (__v8hi)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epi16(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtruew ((__v8hi)__A, (__v8hi)__B); +} + +/*pcom (integer, signed double words) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltd ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomled ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtd ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomged ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomeqd ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomneqd ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalsed ((__v4si)__A, (__v4si)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epi32(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtrued ((__v4si)__A, (__v4si)__B); +} + +/*pcom (integer, signed quad words) */ + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comlt_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomltq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comle_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomleq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comgt_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgtq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comge_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomgeq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comeq_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomeqq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comneq_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomneqq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comfalse_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomfalseq ((__v2di)__A, (__v2di)__B); +} + +extern __inline __m128i __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_comtrue_epi64(__m128i __A, __m128i __B) +{ + return (__m128i) __builtin_ia32_vpcomtrueq ((__v2di)__A, (__v2di)__B); +} + +/* FRCZ */ + +extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_frcz_ps (__m128 __A) +{ + return (__m128) __builtin_ia32_vfrczps ((__v4sf)__A); +} + +extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_frcz_pd (__m128d __A) +{ + return (__m128d) __builtin_ia32_vfrczpd ((__v2df)__A); +} + +extern __inline __m128 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_frcz_ss (__m128 __A, __m128 __B) +{ + return (__m128) __builtin_ia32_vfrczss ((__v4sf)__A, (__v4sf)__B); +} + +extern __inline __m128d __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm_frcz_sd (__m128d __A, __m128d __B) +{ + return (__m128d) __builtin_ia32_vfrczsd ((__v2df)__A, (__v2df)__B); +} + +extern __inline __m256 __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_frcz_ps (__m256 __A) +{ + return (__m256) __builtin_ia32_vfrczps256 ((__v8sf)__A); +} + +extern __inline __m256d __attribute__((__gnu_inline__, __always_inline__, __artificial__)) +_mm256_frcz_pd (__m256d __A) +{ + return (__m256d) __builtin_ia32_vfrczpd256 ((__v4df)__A); +} + +#endif /* __XOP__ */ + +#endif /* _XOPMMINTRIN_H_INCLUDED */ diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c index 75c8f0ee6c4..8460475bddb 100644 --- a/gcc/config/ia64/ia64.c +++ b/gcc/config/ia64/ia64.c @@ -303,6 +303,7 @@ static enum machine_mode ia64_promote_function_mode (const_tree, const_tree, int); static void ia64_trampoline_init (rtx, tree, rtx); +static void ia64_override_options_after_change (void); /* Table of valid machine attributes. */ static const struct attribute_spec ia64_attribute_table[] = @@ -536,6 +537,9 @@ static const struct attribute_spec ia64_attribute_table[] = #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT ia64_trampoline_init +#undef TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE +#define TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE ia64_override_options_after_change + struct gcc_target targetm = TARGET_INITIALIZER; typedef enum @@ -5496,6 +5500,33 @@ ia64_override_options (void) if (TARGET_AUTO_PIC) target_flags |= MASK_CONST_GP; + /* Numerous experiment shows that IRA based loop pressure + calculation works better for RTL loop invariant motion on targets + with enough (>= 32) registers. It is an expensive optimization. + So it is on only for peak performance. */ + if (optimize >= 3) + flag_ira_loop_pressure = 1; + + + ia64_section_threshold = g_switch_set ? g_switch_value : IA64_DEFAULT_GVALUE; + + init_machine_status = ia64_init_machine_status; + + if (align_functions <= 0) + align_functions = 64; + if (align_loops <= 0) + align_loops = 32; + if (TARGET_ABI_OPEN_VMS) + flag_no_common = 1; + + ia64_override_options_after_change(); +} + +/* Implement targetm.override_options_after_change. */ + +static void +ia64_override_options_after_change (void) +{ ia64_flag_schedule_insns2 = flag_schedule_insns_after_reload; flag_schedule_insns_after_reload = 0; @@ -5517,18 +5548,6 @@ ia64_override_options (void) a transformation. */ flag_auto_inc_dec = 0; } - - ia64_section_threshold = g_switch_set ? g_switch_value : IA64_DEFAULT_GVALUE; - - init_machine_status = ia64_init_machine_status; - - if (align_functions <= 0) - align_functions = 64; - if (align_loops <= 0) - align_loops = 32; - - if (TARGET_ABI_OPEN_VMS) - flag_no_common = 1; } /* Initialize the record of emitted frame related registers. */ diff --git a/gcc/config/m32c/m32c-protos.h b/gcc/config/m32c/m32c-protos.h index e571fe9d25e..42b92feb506 100644 --- a/gcc/config/m32c/m32c-protos.h +++ b/gcc/config/m32c/m32c-protos.h @@ -49,7 +49,6 @@ int m32c_trampoline_size (void); #if defined(RTX_CODE) && defined(TREE_CODE) rtx m32c_function_arg (CUMULATIVE_ARGS *, MM, tree, int); -rtx m32c_function_value (const_tree, const_tree); #endif @@ -75,7 +74,7 @@ bool m32c_immd_dbl_mov (rtx *, MM); rtx m32c_incoming_return_addr_rtx (void); int m32c_legitimate_constant_p (rtx); int m32c_legitimize_reload_address (rtx *, MM, int, int, int); -rtx m32c_libcall_value (MM); +bool m32c_function_value_regno_p (const unsigned int); int m32c_limit_reload_class (MM, int); int m32c_memory_move_cost (MM, int, int); int m32c_modes_tieable_p (MM, MM); diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c index 4eeedb183e7..1085aa7c25a 100644 --- a/gcc/config/m32c/m32c.c +++ b/gcc/config/m32c/m32c.c @@ -81,6 +81,9 @@ static bool m32c_strict_argument_naming (CUMULATIVE_ARGS *); static rtx m32c_struct_value_rtx (tree, int); static rtx m32c_subreg (enum machine_mode, rtx, enum machine_mode, int); static int need_to_save (int); +static rtx m32c_function_value (const_tree, const_tree, bool); +static rtx m32c_libcall_value (enum machine_mode, const_rtx); + int current_function_special_page_vector (rtx); #define SYMBOL_FLAG_FUNCVEC_FUNCTION (SYMBOL_FLAG_MACH_DEP << 0) @@ -1591,15 +1594,19 @@ m32c_valid_pointer_mode (enum machine_mode mode) /* How Scalar Function Values Are Returned */ -/* Implements LIBCALL_VALUE. Most values are returned in $r0, or some +/* Implements TARGET_LIBCALL_VALUE. Most values are returned in $r0, or some combination of registers starting there (r2r0 for longs, r3r1r2r0 for long long, r3r2r1r0 for doubles), except that that ABI currently doesn't work because it ends up using all available general registers and gcc often can't compile it. So, instead, we return anything bigger than 16 bits in "mem0" (effectively, a memory location). */ -rtx -m32c_libcall_value (enum machine_mode mode) + +#undef TARGET_LIBCALL_VALUE +#define TARGET_LIBCALL_VALUE m32c_libcall_value + +static rtx +m32c_libcall_value (enum machine_mode mode, const_rtx fun ATTRIBUTE_UNUSED) { /* return reg or parallel */ #if 0 @@ -1649,14 +1656,28 @@ m32c_libcall_value (enum machine_mode mode) return gen_rtx_REG (mode, R0_REGNO); } -/* Implements FUNCTION_VALUE. Functions and libcalls have the same +/* Implements TARGET_FUNCTION_VALUE. Functions and libcalls have the same conventions. */ -rtx -m32c_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE m32c_function_value + +static rtx +m32c_function_value (const_tree valtype, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) { /* return reg or parallel */ const enum machine_mode mode = TYPE_MODE (valtype); - return m32c_libcall_value (mode); + return m32c_libcall_value (mode, NULL_RTX); +} + +/* Implements FUNCTION_VALUE_REGNO_P. */ + +bool +m32c_function_value_regno_p (const unsigned int regno) +{ + return (regno == R0_REGNO || regno == MEM0_REGNO); } /* How Large Values Are Returned */ diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h index 0f12158c0e4..78e3115c291 100644 --- a/gcc/config/m32c/m32c.h +++ b/gcc/config/m32c/m32c.h @@ -533,10 +533,7 @@ typedef struct m32c_cumulative_args /* How Scalar Function Values Are Returned */ -#define FUNCTION_VALUE(VT,F) m32c_function_value (VT, F) -#define LIBCALL_VALUE(MODE) m32c_libcall_value (MODE) - -#define FUNCTION_VALUE_REGNO_P(r) ((r) == R0_REGNO || (r) == MEM0_REGNO) +#define FUNCTION_VALUE_REGNO_P(r) m32c_function_value_regno_p (r) /* How Large Values Are Returned */ @@ -563,7 +560,6 @@ typedef struct m32c_cumulative_args #define HAVE_PRE_DECREMENT 1 #define HAVE_POST_INCREMENT 1 -#define CONSTANT_ADDRESS_P(X) CONSTANT_P(X) #define MAX_REGS_PER_ADDRESS 1 /* This is passed to the macros below, so that they can be implemented diff --git a/gcc/config/m68hc11/m68hc11.h b/gcc/config/m68hc11/m68hc11.h index ee0f9f67fca..278ba15c4fa 100644 --- a/gcc/config/m68hc11/m68hc11.h +++ b/gcc/config/m68hc11/m68hc11.h @@ -1108,9 +1108,6 @@ extern unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER]; && (GET_CODE (XEXP (operand, 0)) == POST_INC) \ && (SP_REG_P (XEXP (XEXP (operand, 0), 0)))) -/* 1 if X is an rtx for a constant that is a valid address. */ -#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X)) - /* Maximum number of registers that can appear in a valid memory address */ #define MAX_REGS_PER_ADDRESS 2 diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index 0862936b1b4..8db98fc4f46 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -1399,6 +1399,30 @@ flags_in_68881 (void) return cc_status.flags & CC_IN_68881; } +/* Return true if PARALLEL contains register REGNO. */ +static bool +m68k_reg_present_p (const_rtx parallel, unsigned int regno) +{ + int i; + + if (REG_P (parallel) && REGNO (parallel) == regno) + return true; + + if (GET_CODE (parallel) != PARALLEL) + return false; + + for (i = 0; i < XVECLEN (parallel, 0); ++i) + { + const_rtx x; + + x = XEXP (XVECEXP (parallel, 0, i), 0); + if (REG_P (x) && REGNO (x) == regno) + return true; + } + + return false; +} + /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL_P. */ static bool @@ -1411,6 +1435,26 @@ m68k_ok_for_sibcall_p (tree decl, tree exp) if (CALL_EXPR_STATIC_CHAIN (exp)) return false; + if (!VOID_TYPE_P (TREE_TYPE (DECL_RESULT (cfun->decl)))) + { + /* Check that the return value locations are the same. For + example that we aren't returning a value from the sibling in + a D0 register but then need to transfer it to a A0 register. */ + rtx cfun_value; + rtx call_value; + + cfun_value = FUNCTION_VALUE (TREE_TYPE (DECL_RESULT (cfun->decl)), + cfun->decl); + call_value = FUNCTION_VALUE (TREE_TYPE (exp), decl); + + /* Check that the values are equal or that the result the callee + function returns is superset of what the current function returns. */ + if (!(rtx_equal_p (cfun_value, call_value) + || (REG_P (cfun_value) + && m68k_reg_present_p (call_value, REGNO (cfun_value))))) + return false; + } + kind = m68k_get_function_kind (current_function_decl); if (kind == m68k_fk_normal_function) /* We can always sibcall from a normal function, because it's @@ -5188,6 +5232,9 @@ m68k_libcall_value (enum machine_mode mode) return gen_rtx_REG (mode, m68k_libcall_value_in_a0_p ? A0_REG : D0_REG); } +/* Location in which function value is returned. + NOTE: Due to differences in ABIs, don't call this function directly, + use FUNCTION_VALUE instead. */ rtx m68k_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) { diff --git a/gcc/config/mep/mep.h b/gcc/config/mep/mep.h index 8b00a444ce2..9d286e33b94 100644 --- a/gcc/config/mep/mep.h +++ b/gcc/config/mep/mep.h @@ -567,8 +567,6 @@ typedef struct #define TRAMPOLINE_SIZE 20 -#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) - #define MAX_REGS_PER_ADDRESS 1 #ifdef REG_OK_STRICT diff --git a/gcc/config/mips/iris.h b/gcc/config/mips/iris.h index fce82174e66..373691ee6e1 100644 --- a/gcc/config/mips/iris.h +++ b/gcc/config/mips/iris.h @@ -63,9 +63,6 @@ along with GCC; see the file COPYING3. If not see #undef ASM_FINISH_DECLARE_OBJECT #define ASM_FINISH_DECLARE_OBJECT mips_finish_declare_object -/* The linker needs a space after "-o". */ -#define SWITCHES_NEED_SPACES "o" - /* Specify wchar_t types. */ #undef WCHAR_TYPE #define WCHAR_TYPE (Pmode == DImode ? "int" : "long int") diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index abcc2d421ef..716b7acad82 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -343,5 +343,7 @@ extern void mips_expand_vector_init (rtx, rtx); extern bool mips_eh_uses (unsigned int); extern bool mips_epilogue_uses (unsigned int); extern void mips_final_prescan_insn (rtx, rtx *, int); +extern int mips_trampoline_code_size (void); +extern void mips_function_profiler (FILE *); #endif /* ! GCC_MIPS_PROTOS_H */ diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 1bead599411..c8c1dca25ce 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -126,6 +126,40 @@ along with GCC; see the file COPYING3. If not see /* True if bit BIT is set in VALUE. */ #define BITSET_P(VALUE, BIT) (((VALUE) & (1 << (BIT))) != 0) +/* Return the opcode for a ptr_mode load of the form: + + l[wd] DEST, OFFSET(BASE). */ +#define MIPS_LOAD_PTR(DEST, OFFSET, BASE) \ + (((ptr_mode == DImode ? 0x37 : 0x23) << 26) \ + | ((BASE) << 21) \ + | ((DEST) << 16) \ + | (OFFSET)) + +/* Return the opcode to move register SRC into register DEST. */ +#define MIPS_MOVE(DEST, SRC) \ + ((TARGET_64BIT ? 0x2d : 0x21) \ + | ((DEST) << 11) \ + | ((SRC) << 21)) + +/* Return the opcode for: + + lui DEST, VALUE. */ +#define MIPS_LUI(DEST, VALUE) \ + ((0xf << 26) | ((DEST) << 16) | (VALUE)) + +/* Return the opcode to jump to register DEST. */ +#define MIPS_JR(DEST) \ + (((DEST) << 21) | 0x8) + +/* Return the opcode for: + + bal . + (1 + OFFSET) * 4. */ +#define MIPS_BAL(OFFSET) \ + ((0x1 << 26) | (0x11 << 16) | (OFFSET)) + +/* Return the usual opcode for a nop. */ +#define MIPS_NOP 0 + /* Classifies an address. ADDRESS_REG @@ -285,6 +319,9 @@ struct GTY(()) mips_frame_info { HOST_WIDE_INT acc_sp_offset; HOST_WIDE_INT cop0_sp_offset; + /* Similar, but the value passed to _mcount. */ + HOST_WIDE_INT ra_fp_offset; + /* The offset of arg_pointer_rtx from the bottom of the frame. */ HOST_WIDE_INT arg_pointer_offset; @@ -2410,6 +2447,28 @@ mips_emit_move (rtx dest, rtx src) : emit_move_insn_1 (dest, src)); } +/* Emit an instruction of the form (set TARGET (CODE OP0)). */ + +static void +mips_emit_unary (enum rtx_code code, rtx target, rtx op0) +{ + emit_insn (gen_rtx_SET (VOIDmode, target, + gen_rtx_fmt_e (code, GET_MODE (op0), op0))); +} + +/* Compute (CODE OP0) and store the result in a new register of mode MODE. + Return that new register. */ + +static rtx +mips_force_unary (enum machine_mode mode, enum rtx_code code, rtx op0) +{ + rtx reg; + + reg = gen_reg_rtx (mode); + mips_emit_unary (code, reg, op0); + return reg; +} + /* Emit an instruction of the form (set TARGET (CODE OP0 OP1)). */ static void @@ -3353,10 +3412,11 @@ mips_immediate_operand_p (int code, HOST_WIDE_INT x) /* Return the cost of binary operation X, given that the instruction sequence for a word-sized or smaller operation has cost SINGLE_COST - and that the sequence of a double-word operation has cost DOUBLE_COST. */ + and that the sequence of a double-word operation has cost DOUBLE_COST. + If SPEED is true, optimize for speed otherwise optimize for size. */ static int -mips_binary_cost (rtx x, int single_cost, int double_cost) +mips_binary_cost (rtx x, int single_cost, int double_cost, bool speed) { int cost; @@ -3365,8 +3425,8 @@ mips_binary_cost (rtx x, int single_cost, int double_cost) else cost = single_cost; return (cost - + rtx_cost (XEXP (x, 0), SET, !optimize_size) - + rtx_cost (XEXP (x, 1), GET_CODE (x), !optimize_size)); + + rtx_cost (XEXP (x, 0), SET, speed) + + rtx_cost (XEXP (x, 1), GET_CODE (x), speed)); } /* Return the cost of floating-point multiplications of mode MODE. */ @@ -3436,8 +3496,7 @@ mips_zero_extend_cost (enum machine_mode mode, rtx op) /* Implement TARGET_RTX_COSTS. */ static bool -mips_rtx_costs (rtx x, int code, int outer_code, int *total, - bool speed) +mips_rtx_costs (rtx x, int code, int outer_code, int *total, bool speed) { enum machine_mode mode = GET_MODE (x); bool float_mode_p = FLOAT_MODE_P (mode); @@ -3493,8 +3552,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total, operand needs to be forced into a register, we will often be able to hoist the constant load out of the loop, so the load should not contribute to the cost. */ - if (!optimize_size - || mips_immediate_operand_p (outer_code, INTVAL (x))) + if (speed || mips_immediate_operand_p (outer_code, INTVAL (x))) { *total = 0; return true; @@ -3592,7 +3650,8 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total, case IOR: case XOR: /* Double-word operations use two single-word operations. */ - *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (2)); + *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (2), + speed); return true; case ASHIFT: @@ -3601,9 +3660,11 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total, case ROTATE: case ROTATERT: if (CONSTANT_P (XEXP (x, 1))) - *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (4)); + *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (4), + speed); else - *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (12)); + *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (12), + speed); return true; case ABS: @@ -3639,7 +3700,8 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total, *total = mips_cost->fp_add; return false; } - *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (4)); + *total = mips_binary_cost (x, COSTS_N_INSNS (1), COSTS_N_INSNS (4), + speed); return true; case MINUS: @@ -3690,7 +3752,8 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total, an SLTU. The MIPS16 version then needs to move the result of the SLTU from $24 to a MIPS16 register. */ *total = mips_binary_cost (x, COSTS_N_INSNS (1), - COSTS_N_INSNS (TARGET_MIPS16 ? 5 : 4)); + COSTS_N_INSNS (TARGET_MIPS16 ? 5 : 4), + speed); return true; case NEG: @@ -3726,10 +3789,10 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total, else if (mode == DImode && !TARGET_64BIT) /* Synthesized from 2 mulsi3s, 1 mulsidi3 and two additions, where the mulsidi3 always includes an MFHI and an MFLO. */ - *total = (optimize_size - ? COSTS_N_INSNS (ISA_HAS_MUL3 ? 7 : 9) - : mips_cost->int_mult_si * 3 + 6); - else if (optimize_size) + *total = (speed + ? mips_cost->int_mult_si * 3 + 6 + : COSTS_N_INSNS (ISA_HAS_MUL3 ? 7 : 9)); + else if (!speed) *total = (ISA_HAS_MUL3 ? 1 : 2); else if (mode == DImode) *total = mips_cost->int_mult_di; @@ -3766,7 +3829,7 @@ mips_rtx_costs (rtx x, int code, int outer_code, int *total, case UDIV: case UMOD: - if (optimize_size) + if (!speed) { /* It is our responsibility to make division by a power of 2 as cheap as 2 register additions if we want the division @@ -6243,7 +6306,7 @@ mips16_build_call_stub (rtx retval, rtx *fn_ptr, rtx args_size, int fp_code) The stub's caller knows that $18 might be clobbered, even though $18 is usually a call-saved register. */ fprintf (asm_out_file, "\tmove\t%s,%s\n", - reg_names[GP_REG_FIRST + 18], reg_names[GP_REG_FIRST + 31]); + reg_names[GP_REG_FIRST + 18], reg_names[RETURN_ADDR_REGNUM]); output_asm_insn (MIPS_CALL ("jal", &fn, 0, -1), &fn); /* Move the result from floating-point registers to @@ -6651,7 +6714,14 @@ mips_expand_block_move (rtx dest, rtx src, rtx length) void mips_expand_synci_loop (rtx begin, rtx end) { - rtx inc, label, cmp, cmp_result; + rtx inc, label, end_label, cmp_result, mask, length; + + /* Create end_label. */ + end_label = gen_label_rtx (); + + /* Check if begin equals end. */ + cmp_result = gen_rtx_EQ (VOIDmode, begin, end); + emit_jump_insn (gen_condjump (cmp_result, end_label)); /* Load INC with the cache line size (rdhwr INC,$1). */ inc = gen_reg_rtx (Pmode); @@ -6659,18 +6729,36 @@ mips_expand_synci_loop (rtx begin, rtx end) ? gen_rdhwr_synci_step_si (inc) : gen_rdhwr_synci_step_di (inc)); + /* Check if inc is 0. */ + cmp_result = gen_rtx_EQ (VOIDmode, inc, const0_rtx); + emit_jump_insn (gen_condjump (cmp_result, end_label)); + + /* Calculate mask. */ + mask = mips_force_unary (Pmode, NEG, inc); + + /* Mask out begin by mask. */ + begin = mips_force_binary (Pmode, AND, begin, mask); + + /* Calculate length. */ + length = mips_force_binary (Pmode, MINUS, end, begin); + /* Loop back to here. */ label = gen_label_rtx (); emit_label (label); emit_insn (gen_synci (begin)); - cmp = mips_force_binary (Pmode, GTU, begin, end); + /* Update length. */ + mips_emit_binary (MINUS, length, length, inc); + /* Update begin. */ mips_emit_binary (PLUS, begin, begin, inc); - cmp_result = gen_rtx_EQ (VOIDmode, cmp, const0_rtx); + /* Check if length is greater than 0. */ + cmp_result = gen_rtx_GT (VOIDmode, length, const0_rtx); emit_jump_insn (gen_condjump (cmp_result, label)); + + emit_label (end_label); } /* Expand a QI or HI mode atomic memory operation. @@ -7276,7 +7364,7 @@ mips_print_operand_punctuation (FILE *file, int ch) break; case '@': - fputs (reg_names[GP_REG_FIRST + 1], file); + fputs (reg_names[AT_REGNUM], file); break; case '^': @@ -8144,8 +8232,8 @@ mips_frame_set (rtx mem, rtx reg) /* If we're saving the return address register and the DWARF return address column differs from the hard register number, adjust the note reg to refer to the former. */ - if (REGNO (reg) == GP_REG_FIRST + 31 - && DWARF_FRAME_RETURN_COLUMN != GP_REG_FIRST + 31) + if (REGNO (reg) == RETURN_ADDR_REGNUM + && DWARF_FRAME_RETURN_COLUMN != RETURN_ADDR_REGNUM) reg = gen_rtx_REG (GET_MODE (reg), DWARF_FRAME_RETURN_COLUMN); set = gen_rtx_SET (VOIDmode, mem, reg); @@ -8595,8 +8683,8 @@ mips16e_output_save_restore (rtx pattern, HOST_WIDE_INT adjust) mips16e_a0_a3_regs[end - 1]); /* Save or restore $31. */ - if (BITSET_P (info.mask, 31)) - s += sprintf (s, ",%s", reg_names[GP_REG_FIRST + 31]); + if (BITSET_P (info.mask, RETURN_ADDR_REGNUM)) + s += sprintf (s, ",%s", reg_names[RETURN_ADDR_REGNUM]); return buffer; } @@ -8764,7 +8852,7 @@ mips_global_pointer (void) return GLOBAL_POINTER_REGNUM; } -/* Return true if current function's prologue must load the global +/* Return true if the current function's prologue must load the global pointer value into pic_offset_table_rtx and store the same value in the function's cprestore slot (if any). @@ -8969,7 +9057,7 @@ mips_cfun_might_clobber_call_saved_reg_p (unsigned int regno) /* If a MIPS16 function returns a value in FPRs, its epilogue will need to call an external libgcc routine. This yet-to-be generated call_insn will clobber $31. */ - if (regno == GP_REG_FIRST + 31 && mips16_cfun_returns_in_fpr_p ()) + if (regno == RETURN_ADDR_REGNUM && mips16_cfun_returns_in_fpr_p ()) return true; /* If REGNO is ordinarily call-clobbered, we must assume that any @@ -9003,7 +9091,7 @@ mips_save_reg_p (unsigned int regno) /* We need to save the incoming return address if __builtin_eh_return is being used to set a different return address. */ - if (regno == GP_REG_FIRST + 31 && crtl->calls_eh_return) + if (regno == RETURN_ADDR_REGNUM && crtl->calls_eh_return) return true; return false; @@ -9378,7 +9466,7 @@ mips_return_addr (int count, rtx frame ATTRIBUTE_UNUSED) if (count != 0) return const0_rtx; - return get_hard_reg_initial_val (Pmode, GP_REG_FIRST + 31); + return get_hard_reg_initial_val (Pmode, RETURN_ADDR_REGNUM); } /* Emit code to change the current function's return address to @@ -9390,7 +9478,7 @@ mips_set_return_address (rtx address, rtx scratch) { rtx slot_address; - gcc_assert (BITSET_P (cfun->machine->frame.mask, 31)); + gcc_assert (BITSET_P (cfun->machine->frame.mask, RETURN_ADDR_REGNUM)); slot_address = mips_add_offset (scratch, stack_pointer_rtx, cfun->machine->frame.gp_sp_offset); mips_emit_move (gen_frame_mem (GET_MODE (address), slot_address), address); @@ -9499,7 +9587,10 @@ mips_restore_gp_from_cprestore_slot (rtx temp) gcc_assert (TARGET_ABICALLS && TARGET_OLDABI && epilogue_completed); if (!cfun->machine->must_restore_gp_when_clobbered_p) - return; + { + emit_note (NOTE_INSN_DELETED); + return; + } if (TARGET_MIPS16) { @@ -9578,6 +9669,9 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_offset, for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--) if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST)) { + /* Record the ra offset for use by mips_function_profiler. */ + if (regno == RETURN_ADDR_REGNUM) + cfun->machine->frame.ra_fp_offset = offset + sp_offset; mips_save_restore_reg (word_mode, regno, offset, fn); offset -= UNITS_PER_WORD; } @@ -9604,7 +9698,7 @@ static bool mips_direct_save_slot_move_p (unsigned int regno, rtx mem, bool load_p) { /* There is a specific MIPS16 instruction for saving $31 to the stack. */ - if (TARGET_MIPS16 && !load_p && regno == GP_REG_FIRST + 31) + if (TARGET_MIPS16 && !load_p && regno == RETURN_ADDR_REGNUM) return false; return mips_secondary_reload_class (REGNO_REG_CLASS (regno), @@ -9741,7 +9835,7 @@ mips_output_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED) (frame_pointer_needed ? frame->total_size - frame->hard_frame_pointer_offset : frame->total_size), - reg_names[GP_REG_FIRST + 31], + reg_names[RETURN_ADDR_REGNUM], frame->var_size, frame->num_gp, frame->num_fp, frame->args_size, @@ -10184,7 +10278,7 @@ mips_restore_reg (rtx reg, rtx mem) { /* There's no MIPS16 instruction to load $31 directly. Load into $7 instead and adjust the return insn appropriately. */ - if (TARGET_MIPS16 && REGNO (reg) == GP_REG_FIRST + 31) + if (TARGET_MIPS16 && REGNO (reg) == RETURN_ADDR_REGNUM) reg = gen_rtx_REG (GET_MODE (reg), GP_REG_FIRST + 7); mips_emit_save_slot_move (reg, mem, MIPS_EPILOGUE_TEMP (GET_MODE (reg))); @@ -10399,10 +10493,10 @@ mips_expand_epilogue (bool sibcall_p) address into $7 rather than $31. */ if (TARGET_MIPS16 && !GENERATE_MIPS16E_SAVE_RESTORE - && BITSET_P (frame->mask, 31)) + && BITSET_P (frame->mask, RETURN_ADDR_REGNUM)) regno = GP_REG_FIRST + 7; else - regno = GP_REG_FIRST + 31; + regno = RETURN_ADDR_REGNUM; emit_jump_insn (gen_return_internal (gen_rtx_REG (Pmode, regno))); } } @@ -15830,7 +15924,7 @@ mips_epilogue_uses (unsigned int regno) /* Say that the epilogue uses the return address register. Note that in the case of sibcalls, the values "used by the epilogue" are considered live at the start of the called function. */ - if (regno == 31) + if (regno == RETURN_ADDR_REGNUM) return true; /* If using a GOT, say that the epilogue also uses GOT_VERSION_REGNUM. @@ -15889,41 +15983,21 @@ mips_final_postscan_insn (FILE *file ATTRIBUTE_UNUSED, rtx insn, mips_pop_asm_switch (&mips_noat); } -/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE. */ +/* Return the size in bytes of the trampoline code, padded to + TRAMPOLINE_ALIGNMENT bits. The static chain pointer and target + function address immediately follow. */ -static void -mips_asm_trampoline_template (FILE *f) -{ - if (ptr_mode == DImode) - fprintf (f, "\t.word\t0x03e0082d\t\t# dmove $1,$31\n"); - else - fprintf (f, "\t.word\t0x03e00821\t\t# move $1,$31\n"); - fprintf (f, "\t.word\t0x04110001\t\t# bgezal $0,.+8\n"); - fprintf (f, "\t.word\t0x00000000\t\t# nop\n"); - if (ptr_mode == DImode) - { - fprintf (f, "\t.word\t0xdff90014\t\t# ld $25,20($31)\n"); - fprintf (f, "\t.word\t0xdfef001c\t\t# ld $15,28($31)\n"); - } - else - { - fprintf (f, "\t.word\t0x8ff90010\t\t# lw $25,16($31)\n"); - fprintf (f, "\t.word\t0x8fef0014\t\t# lw $15,20($31)\n"); - } - fprintf (f, "\t.word\t0x03200008\t\t# jr $25\n"); - if (ptr_mode == DImode) - { - fprintf (f, "\t.word\t0x0020f82d\t\t# dmove $31,$1\n"); - fprintf (f, "\t.word\t0x00000000\t\t# \n"); - fprintf (f, "\t.dword\t0x00000000\t\t# \n"); - fprintf (f, "\t.dword\t0x00000000\t\t# \n"); - } +int +mips_trampoline_code_size (void) +{ + if (TARGET_USE_PIC_FN_ADDR_REG) + return 4 * 4; + else if (ptr_mode == DImode) + return 8 * 4; + else if (ISA_HAS_LOAD_DELAY) + return 6 * 4; else - { - fprintf (f, "\t.word\t0x0020f821\t\t# move $31,$1\n"); - fprintf (f, "\t.word\t0x00000000\t\t# \n"); - fprintf (f, "\t.word\t0x00000000\t\t# \n"); - } + return 4 * 4; } /* Implement TARGET_TRAMPOLINE_INIT. */ @@ -15931,23 +16005,198 @@ mips_asm_trampoline_template (FILE *f) static void mips_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) { - rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); - rtx mem, addr, end_addr; + rtx addr, end_addr, high, low, opcode, mem; + rtx trampoline[8]; + unsigned int i, j; + HOST_WIDE_INT end_addr_offset, static_chain_offset, target_function_offset; + + /* Work out the offsets of the pointers from the start of the + trampoline code. */ + end_addr_offset = mips_trampoline_code_size (); + static_chain_offset = end_addr_offset; + target_function_offset = static_chain_offset + GET_MODE_SIZE (ptr_mode); - emit_block_move (m_tramp, assemble_trampoline_template (), - GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); + /* Get pointers to the beginning and end of the code block. */ + addr = force_reg (Pmode, XEXP (m_tramp, 0)); + end_addr = mips_force_binary (Pmode, PLUS, addr, GEN_INT (end_addr_offset)); + +#define OP(X) gen_int_mode (X, SImode) + + /* Build up the code in TRAMPOLINE. */ + i = 0; + if (TARGET_USE_PIC_FN_ADDR_REG) + { + /* $25 contains the address of the trampoline. Emit code of the form: + + l[wd] $1, target_function_offset($25) + l[wd] $static_chain, static_chain_offset($25) + jr $1 + move $25,$1. */ + trampoline[i++] = OP (MIPS_LOAD_PTR (AT_REGNUM, + target_function_offset, + PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM, + static_chain_offset, + PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_JR (AT_REGNUM)); + trampoline[i++] = OP (MIPS_MOVE (PIC_FUNCTION_ADDR_REGNUM, AT_REGNUM)); + } + else if (ptr_mode == DImode) + { + /* It's too cumbersome to create the full 64-bit address, so let's + instead use: + + move $1, $31 + bal 1f + nop + 1: l[wd] $25, target_function_offset - 12($31) + l[wd] $static_chain, static_chain_offset - 12($31) + jr $25 + move $31, $1 + + where 12 is the offset of "1:" from the start of the code block. */ + trampoline[i++] = OP (MIPS_MOVE (AT_REGNUM, RETURN_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_BAL (1)); + trampoline[i++] = OP (MIPS_NOP); + trampoline[i++] = OP (MIPS_LOAD_PTR (PIC_FUNCTION_ADDR_REGNUM, + target_function_offset - 12, + RETURN_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM, + static_chain_offset - 12, + RETURN_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_MOVE (RETURN_ADDR_REGNUM, AT_REGNUM)); + } + else + { + /* If the target has load delays, emit: + + lui $1, %hi(end_addr) + lw $25, %lo(end_addr + ...)($1) + lw $static_chain, %lo(end_addr + ...)($1) + jr $25 + nop + + Otherwise emit: + + lui $1, %hi(end_addr) + lw $25, %lo(end_addr + ...)($1) + jr $25 + lw $static_chain, %lo(end_addr + ...)($1). */ + + /* Split END_ADDR into %hi and %lo values. Trampolines are aligned + to 64 bits, so the %lo value will have the bottom 3 bits clear. */ + high = expand_simple_binop (SImode, PLUS, end_addr, GEN_INT (0x8000), + NULL, false, OPTAB_WIDEN); + high = expand_simple_binop (SImode, LSHIFTRT, high, GEN_INT (16), + NULL, false, OPTAB_WIDEN); + low = convert_to_mode (SImode, gen_lowpart (HImode, end_addr), true); + + /* Emit the LUI. */ + opcode = OP (MIPS_LUI (AT_REGNUM, 0)); + trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, high, + NULL, false, OPTAB_WIDEN); + + /* Emit the load of the target function. */ + opcode = OP (MIPS_LOAD_PTR (PIC_FUNCTION_ADDR_REGNUM, + target_function_offset - end_addr_offset, + AT_REGNUM)); + trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, low, + NULL, false, OPTAB_WIDEN); + + /* Emit the JR here, if we can. */ + if (!ISA_HAS_LOAD_DELAY) + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM)); + + /* Emit the load of the static chain register. */ + opcode = OP (MIPS_LOAD_PTR (STATIC_CHAIN_REGNUM, + static_chain_offset - end_addr_offset, + AT_REGNUM)); + trampoline[i++] = expand_simple_binop (SImode, IOR, opcode, low, + NULL, false, OPTAB_WIDEN); + + /* Emit the JR, if we couldn't above. */ + if (ISA_HAS_LOAD_DELAY) + { + trampoline[i++] = OP (MIPS_JR (PIC_FUNCTION_ADDR_REGNUM)); + trampoline[i++] = OP (MIPS_NOP); + } + } - mem = adjust_address (m_tramp, ptr_mode, ptr_mode == DImode ? 32 : 28); - mips_emit_move (mem, force_reg (ptr_mode, fnaddr)); - mem = adjust_address (mem, ptr_mode, GET_MODE_SIZE (ptr_mode)); - mips_emit_move (mem, force_reg (ptr_mode, chain_value)); +#undef OP - addr = force_reg (ptr_mode, XEXP (m_tramp, 0)); - end_addr = gen_reg_rtx (ptr_mode); + /* Copy the trampoline code. Leave any padding uninitialized. */ + for (j = 0; j < i; j++) + { + mem = adjust_address (m_tramp, SImode, j * GET_MODE_SIZE (SImode)); + mips_emit_move (mem, trampoline[j]); + } + + /* Set up the static chain pointer field. */ + mem = adjust_address (m_tramp, ptr_mode, static_chain_offset); + mips_emit_move (mem, chain_value); + + /* Set up the target function field. */ + mem = adjust_address (m_tramp, ptr_mode, target_function_offset); + mips_emit_move (mem, XEXP (DECL_RTL (fndecl), 0)); + + /* Flush the code part of the trampoline. */ emit_insn (gen_add3_insn (end_addr, addr, GEN_INT (TRAMPOLINE_SIZE))); emit_insn (gen_clear_cache (addr, end_addr)); } +/* Implement FUNCTION_PROFILER. */ + +void mips_function_profiler (FILE *file) +{ + if (TARGET_MIPS16) + sorry ("mips16 function profiling"); + if (TARGET_LONG_CALLS) + { + /* For TARGET_LONG_CALLS use $3 for the address of _mcount. */ + if (Pmode == DImode) + fprintf (file, "\tdla\t%s,_mcount\n", reg_names[3]); + else + fprintf (file, "\tla\t%s,_mcount\n", reg_names[3]); + } + mips_push_asm_switch (&mips_noat); + fprintf (file, "\tmove\t%s,%s\t\t# save current return address\n", + reg_names[AT_REGNUM], reg_names[RETURN_ADDR_REGNUM]); + /* _mcount treats $2 as the static chain register. */ + if (cfun->static_chain_decl != NULL) + fprintf (file, "\tmove\t%s,%s\n", reg_names[2], + reg_names[STATIC_CHAIN_REGNUM]); + if (TARGET_MCOUNT_RA_ADDRESS) + { + /* If TARGET_MCOUNT_RA_ADDRESS load $12 with the address of the + ra save location. */ + if (cfun->machine->frame.ra_fp_offset == 0) + /* ra not saved, pass zero. */ + fprintf (file, "\tmove\t%s,%s\n", reg_names[12], reg_names[0]); + else + fprintf (file, "\t%s\t%s," HOST_WIDE_INT_PRINT_DEC "(%s)\n", + Pmode == DImode ? "dla" : "la", reg_names[12], + cfun->machine->frame.ra_fp_offset, + reg_names[STACK_POINTER_REGNUM]); + } + if (!TARGET_NEWABI) + fprintf (file, + "\t%s\t%s,%s,%d\t\t# _mcount pops 2 words from stack\n", + TARGET_64BIT ? "dsubu" : "subu", + reg_names[STACK_POINTER_REGNUM], + reg_names[STACK_POINTER_REGNUM], + Pmode == DImode ? 16 : 8); + + if (TARGET_LONG_CALLS) + fprintf (file, "\tjalr\t%s\n", reg_names[3]); + else + fprintf (file, "\tjal\t_mcount\n"); + mips_pop_asm_switch (&mips_noat); + /* _mcount treats $2 as the static chain register. */ + if (cfun->static_chain_decl != NULL) + fprintf (file, "\tmove\t%s,%s\n", reg_names[STATIC_CHAIN_REGNUM], + reg_names[2]); +} /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP @@ -16129,8 +16378,6 @@ mips_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value) #undef TARGET_CAN_ELIMINATE #define TARGET_CAN_ELIMINATE mips_can_eliminate -#undef TARGET_ASM_TRAMPOLINE_TEMPLATE -#define TARGET_ASM_TRAMPOLINE_TEMPLATE mips_asm_trampoline_template #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT mips_trampoline_init diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 934e0fafa90..282970890f8 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -1311,10 +1311,10 @@ enum mips_code_readable_setting { #define DWARF_FRAME_REGNUM(REGNO) mips_dwarf_regno[REGNO] /* The DWARF 2 CFA column which tracks the return address. */ -#define DWARF_FRAME_RETURN_COLUMN (GP_REG_FIRST + 31) +#define DWARF_FRAME_RETURN_COLUMN RETURN_ADDR_REGNUM /* Before the prologue, RA lives in r31. */ -#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, GP_REG_FIRST + 31) +#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (VOIDmode, RETURN_ADDR_REGNUM) /* Describe how we implement __builtin_eh_return. */ #define EH_RETURN_DATA_REGNO(N) \ @@ -2372,44 +2372,7 @@ typedef struct mips_args { /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. */ -#define FUNCTION_PROFILER(FILE, LABELNO) \ -{ \ - if (TARGET_MIPS16) \ - sorry ("mips16 function profiling"); \ - if (TARGET_LONG_CALLS) \ - { \ - /* For TARGET_LONG_CALLS use $3 for the address of _mcount. */ \ - if (Pmode == DImode) \ - fprintf (FILE, "\tdla\t%s,_mcount\n", reg_names[GP_REG_FIRST + 3]); \ - else \ - fprintf (FILE, "\tla\t%s,_mcount\n", reg_names[GP_REG_FIRST + 3]); \ - } \ - mips_push_asm_switch (&mips_noat); \ - fprintf (FILE, "\tmove\t%s,%s\t\t# save current return address\n", \ - reg_names[GP_REG_FIRST + 1], reg_names[GP_REG_FIRST + 31]); \ - /* _mcount treats $2 as the static chain register. */ \ - if (cfun->static_chain_decl != NULL) \ - fprintf (FILE, "\tmove\t%s,%s\n", reg_names[2], \ - reg_names[STATIC_CHAIN_REGNUM]); \ - if (!TARGET_NEWABI) \ - { \ - fprintf (FILE, \ - "\t%s\t%s,%s,%d\t\t# _mcount pops 2 words from stack\n", \ - TARGET_64BIT ? "dsubu" : "subu", \ - reg_names[STACK_POINTER_REGNUM], \ - reg_names[STACK_POINTER_REGNUM], \ - Pmode == DImode ? 16 : 8); \ - } \ - if (TARGET_LONG_CALLS) \ - fprintf (FILE, "\tjalr\t%s\n", reg_names[GP_REG_FIRST + 3]); \ - else \ - fprintf (FILE, "\tjal\t_mcount\n"); \ - mips_pop_asm_switch (&mips_noat); \ - /* _mcount treats $2 as the static chain register. */ \ - if (cfun->static_chain_decl != NULL) \ - fprintf (FILE, "\tmove\t%s,%s\n", reg_names[STATIC_CHAIN_REGNUM], \ - reg_names[2]); \ -} +#define FUNCTION_PROFILER(FILE, LABELNO) mips_function_profiler ((FILE)) /* The profiler preserves all interesting registers, including $31. */ #define MIPS_SAVE_REG_FOR_PROFILING_P(REGNO) false @@ -2433,14 +2396,15 @@ typedef struct mips_args { #define EXIT_IGNORE_STACK 1 -/* A C expression for the size in bytes of the trampoline, as an - integer. */ +/* Trampolines are a block of code followed by two pointers. */ -#define TRAMPOLINE_SIZE (ptr_mode == DImode ? 48 : 36) +#define TRAMPOLINE_SIZE \ + (mips_trampoline_code_size () + GET_MODE_SIZE (ptr_mode) * 2) -/* Alignment required for trampolines, in bits. */ +/* Forcing a 64-bit alignment for 32-bit targets allows us to load two + pointers from a single LUI base. */ -#define TRAMPOLINE_ALIGNMENT GET_MODE_BITSIZE (ptr_mode) +#define TRAMPOLINE_ALIGNMENT 64 /* mips_trampoline_init calls this library function to flush program and data caches. */ diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index 19f3ffc7a06..76fc37bd479 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -82,6 +82,7 @@ (UNSPEC_ADDRESS_FIRST 100) (TLS_GET_TP_REGNUM 3) + (RETURN_ADDR_REGNUM 31) (CPRESTORE_SLOT_REGNUM 76) (GOT_VERSION_REGNUM 79) @@ -1878,7 +1879,7 @@ (set_attr "mode" "SI") (set_attr "length" "12")]) -(define_insn_and_split "mulsidi3_64bit" +(define_insn "mulsidi3_64bit" [(set (match_operand:DI 0 "register_operand" "=d") (mult:DI (any_extend:DI (match_operand:SI 1 "register_operand" "d")) (any_extend:DI (match_operand:SI 2 "register_operand" "d")))) @@ -1886,37 +1887,67 @@ (clobber (match_scratch:DI 4 "=d"))] "TARGET_64BIT && !TARGET_FIX_R4000" "#" - "&& reload_completed" + [(set_attr "type" "imul") + (set_attr "mode" "SI") + (set (attr "length") + (if_then_else (ne (symbol_ref "ISA_HAS_EXT_INS") (const_int 0)) + (const_int 16) + (const_int 28)))]) + +(define_split + [(set (match_operand:DI 0 "d_operand") + (mult:DI (any_extend:DI (match_operand:SI 1 "d_operand")) + (any_extend:DI (match_operand:SI 2 "d_operand")))) + (clobber (match_operand:TI 3 "hilo_operand")) + (clobber (match_operand:DI 4 "d_operand"))] + "TARGET_64BIT && !TARGET_FIX_R4000 && ISA_HAS_EXT_INS && reload_completed" [(set (match_dup 3) (unspec:TI [(mult:DI (any_extend:DI (match_dup 1)) (any_extend:DI (match_dup 2)))] UNSPEC_SET_HILO)) - ;; OP4 <- LO, OP0 <- HI - (set (match_dup 4) (match_dup 5)) - (set (match_dup 0) (unspec:DI [(match_dup 3)] UNSPEC_MFHI)) + ;; OP0 <- LO, OP4 <- HI + (set (match_dup 0) (match_dup 5)) + (set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI)) - ;; Zero-extend OP4. - (set (match_dup 4) - (ashift:DI (match_dup 4) - (const_int 32))) - (set (match_dup 4) - (lshiftrt:DI (match_dup 4) - (const_int 32))) + (set (zero_extract:DI (match_dup 0) (const_int 32) (const_int 32)) + (match_dup 4))] + { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); }) + +(define_split + [(set (match_operand:DI 0 "d_operand") + (mult:DI (any_extend:DI (match_operand:SI 1 "d_operand")) + (any_extend:DI (match_operand:SI 2 "d_operand")))) + (clobber (match_operand:TI 3 "hilo_operand")) + (clobber (match_operand:DI 4 "d_operand"))] + "TARGET_64BIT && !TARGET_FIX_R4000 && !ISA_HAS_EXT_INS && reload_completed" + [(set (match_dup 3) + (unspec:TI [(mult:DI (any_extend:DI (match_dup 1)) + (any_extend:DI (match_dup 2)))] + UNSPEC_SET_HILO)) + + ;; OP0 <- LO, OP4 <- HI + (set (match_dup 0) (match_dup 5)) + (set (match_dup 4) (unspec:DI [(match_dup 3)] UNSPEC_MFHI)) - ;; Shift OP0 into place. + ;; Zero-extend OP0. (set (match_dup 0) (ashift:DI (match_dup 0) (const_int 32))) + (set (match_dup 0) + (lshiftrt:DI (match_dup 0) + (const_int 32))) + + ;; Shift OP4 into place. + (set (match_dup 4) + (ashift:DI (match_dup 4) + (const_int 32))) ;; OR the two halves together (set (match_dup 0) (ior:DI (match_dup 0) (match_dup 4)))] - { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); } - [(set_attr "type" "imul") - (set_attr "mode" "SI") - (set_attr "length" "24")]) + { operands[5] = gen_rtx_REG (DImode, LO_REGNUM); }) (define_insn "mulsidi3_64bit_hilo" [(set (match_operand:TI 0 "register_operand" "=x") @@ -4011,7 +4042,7 @@ (define_insn "*mov_ra" [(set (match_operand:GPR 0 "stack_operand" "=m") - (reg:GPR 31))] + (reg:GPR RETURN_ADDR_REGNUM))] "TARGET_MIPS16" "\t$31,%0" [(set_attr "move_type" "store") @@ -4938,7 +4969,7 @@ (define_insn "clear_hazard_" [(unspec_volatile [(const_int 0)] UNSPEC_CLEAR_HAZARD) - (clobber (reg:P 31))] + (clobber (reg:P RETURN_ADDR_REGNUM))] "ISA_HAS_SYNCI" { return "%(%. + +;; PPC476 Embedded PowerPC controller +;; 3 issue (476) / 4 issue (476fp) +;; +;; i_pipe - complex integer / compare +;; lj_pipe - load-store / simple integer arithmetic +;; b_pipe - branch pipe +;; f_pipe - floating point arithmetic + +(define_automaton "ppc476_core,ppc476_apu") + +(define_cpu_unit "ppc476_i_pipe,ppc476_lj_pipe,ppc476_b_pipe" "ppc476_core") +(define_cpu_unit "ppc476_issue_fp,ppc476_f_pipe" "ppc476_apu") +(define_cpu_unit "ppc476_issue_0,ppc476_issue_1,ppc476_issue_2" "ppc476_core") + +(define_reservation "ppc476_issue" "ppc476_issue_0|ppc476_issue_1|ppc476_issue_2") +(define_reservation "ppc476_issue2" "ppc476_issue_0+ppc476_issue_1\ + |ppc476_issue_0+ppc476_issue_2\ + |ppc476_issue_1+ppc476_issue_2") +(define_reservation "ppc476_issue3" "ppc476_issue_0+ppc476_issue_1+ppc476_issue_2") + +(define_insn_reservation "ppc476-load" 4 + (and (eq_attr "type" "load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,\ + load_l,store_c,sync") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_lj_pipe") + +(define_insn_reservation "ppc476-store" 4 + (and (eq_attr "type" "store,store_ux,store_u") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_lj_pipe") + +(define_insn_reservation "ppc476-fpload" 4 + (and (eq_attr "type" "fpload,fpload_ux,fpload_u") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_lj_pipe") + +(define_insn_reservation "ppc476-fpstore" 4 + (and (eq_attr "type" "fpstore,fpstore_ux,fpstore_u") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_lj_pipe") + +(define_insn_reservation "ppc476-simple-integer" 1 + (and (eq_attr "type" "integer,insert_word,var_shift_rotate,exts,shift") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_i_pipe|ppc476_lj_pipe") + +(define_insn_reservation "ppc476-complex-integer" 1 + (and (eq_attr "type" "cmp,cr_logical,delayed_cr,cntlz,isel,isync,sync,trap") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_i_pipe") + +(define_insn_reservation "ppc476-compare" 4 + (and (eq_attr "type" "compare,delayed_compare,fast_compare,mfcr,mfcrf,\ + mtcr,mfjmpr,mtjmpr,var_delayed_compare") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_i_pipe") + +(define_insn_reservation "ppc476-imul" 4 + (and (eq_attr "type" "imul,imul_compare,imul2,imul3") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_i_pipe") + +(define_insn_reservation "ppc476-idiv" 11 + (and (eq_attr "type" "idiv") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_i_pipe*11") + +(define_insn_reservation "ppc476-branch" 1 + (and (eq_attr "type" "branch,jmpreg") + (eq_attr "cpu" "ppc476")) + "ppc476_issue,\ + ppc476_b_pipe") + +(define_insn_reservation "ppc476-two" 2 + (and (eq_attr "type" "two") + (eq_attr "cpu" "ppc476")) + "ppc476_issue2,\ + ppc476_i_pipe|ppc476_lj_pipe,\ + ppc476_i_pipe|ppc476_lj_pipe") + +(define_insn_reservation "ppc476-three" 3 + (and (eq_attr "type" "three") + (eq_attr "cpu" "ppc476")) + "ppc476_issue3,\ + ppc476_i_pipe|ppc476_lj_pipe,\ + ppc476_i_pipe|ppc476_lj_pipe,\ + ppc476_i_pipe|ppc476_lj_pipe") + +(define_insn_reservation "ppc476-fpcompare" 6 + (and (eq_attr "type" "fpcompare") + (eq_attr "cpu" "ppc476")) + "ppc476_issue+ppc476_issue_fp,\ + ppc476_f_pipe+ppc476_i_pipe") + +(define_insn_reservation "ppc476-fp" 6 + (and (eq_attr "type" "fp,dmul") + (eq_attr "cpu" "ppc476")) + "ppc476_issue_fp,\ + ppc476_f_pipe") + +(define_insn_reservation "ppc476-sdiv" 19 + (and (eq_attr "type" "sdiv") + (eq_attr "cpu" "ppc476")) + "ppc476_issue_fp, + ppc476_f_pipe*19") + +(define_insn_reservation "ppc476-ddiv" 33 + (and (eq_attr "type" "ddiv") + (eq_attr "cpu" "ppc476")) + "ppc476_issue_fp,\ + ppc476_f_pipe*33") + diff --git a/gcc/config/rs6000/603.md b/gcc/config/rs6000/603.md index c5fea314819..a042729a1da 100644 --- a/gcc/config/rs6000/603.md +++ b/gcc/config/rs6000/603.md @@ -1,5 +1,5 @@ ;; Scheduling description for PowerPC 603 processor. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -59,7 +59,7 @@ (define_insn_reservation "ppc603-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "ppc603")) "iu_603") diff --git a/gcc/config/rs6000/6xx.md b/gcc/config/rs6000/6xx.md index 88c15ae39ec..b0de9731525 100644 --- a/gcc/config/rs6000/6xx.md +++ b/gcc/config/rs6000/6xx.md @@ -1,6 +1,6 @@ ;; Scheduling description for PowerPC 604, PowerPC 604e, PowerPC 620, ;; and PowerPC 630 processors. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -74,7 +74,7 @@ (define_insn_reservation "ppc604-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "ppc604,ppc604e,ppc620,ppc630")) "iu1_6xx|iu2_6xx") diff --git a/gcc/config/rs6000/7450.md b/gcc/config/rs6000/7450.md index 6f2775744d4..ccaa3b20da3 100644 --- a/gcc/config/rs6000/7450.md +++ b/gcc/config/rs6000/7450.md @@ -1,5 +1,5 @@ ;; Scheduling description for Motorola PowerPC 7450 processor. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -75,7 +75,7 @@ (define_insn_reservation "ppc7450-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,\ - trap,var_shift_rotate,cntlz,exts") + trap,var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "ppc7450")) "ppc7450_du,iu1_7450|iu2_7450|iu3_7450") diff --git a/gcc/config/rs6000/7xx.md b/gcc/config/rs6000/7xx.md index 0129048c07c..edbde75c22a 100644 --- a/gcc/config/rs6000/7xx.md +++ b/gcc/config/rs6000/7xx.md @@ -1,5 +1,5 @@ ;; Scheduling description for Motorola PowerPC 750 and PowerPC 7400 processors. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -65,7 +65,7 @@ (define_insn_reservation "ppc750-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,\ - trap,var_shift_rotate,cntlz,exts") + trap,var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "ppc750,ppc7400")) "ppc750_du,iu1_7xx|iu2_7xx") diff --git a/gcc/config/rs6000/8540.md b/gcc/config/rs6000/8540.md index 2d44b3af94b..4096dff432c 100644 --- a/gcc/config/rs6000/8540.md +++ b/gcc/config/rs6000/8540.md @@ -1,5 +1,5 @@ ;; Pipeline description for Motorola PowerPC 8540 processor. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -86,7 +86,7 @@ (define_insn_reservation "ppc8540_su" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,cmp,compare,\ delayed_compare,var_delayed_compare,fast_compare,\ - shift,trap,var_shift_rotate,cntlz,exts") + shift,trap,var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "ppc8540")) "ppc8540_decode,ppc8540_issue+ppc8540_su_stage0+ppc8540_retire") diff --git a/gcc/config/rs6000/a2.md b/gcc/config/rs6000/a2.md new file mode 100644 index 00000000000..851d8949ff7 --- /dev/null +++ b/gcc/config/rs6000/a2.md @@ -0,0 +1,134 @@ +;; Scheduling description for PowerPC A2 processors. +;; Copyright (C) 2009 Free Software Foundation, Inc. +;; Contributed by Ben Elliston (bje@au.ibm.com) + +;; 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 3, 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 COPYING3. If not see +;; . + +(define_automaton "ppca2") + +;; CPU units + +;; The multiplier pipeline. +(define_cpu_unit "mult" "ppca2") + +;; The auxillary processor unit (FP/vector unit). +(define_cpu_unit "axu" "ppca2") + +;; D.4.6 +;; Some peculiarities for certain SPRs + +(define_insn_reservation "ppca2-mfcr" 1 + (and (eq_attr "type" "mfcr") + (eq_attr "cpu" "ppca2")) + "nothing") + +(define_insn_reservation "ppca2-mfjmpr" 5 + (and (eq_attr "type" "mfjmpr") + (eq_attr "cpu" "ppca2")) + "nothing") + +(define_insn_reservation "ppca2-mtjmpr" 5 + (and (eq_attr "type" "mtjmpr") + (eq_attr "cpu" "ppca2")) + "nothing") + +;; D.4.8 +(define_insn_reservation "ppca2-imul" 1 + (and (eq_attr "type" "imul,imul2,imul3,imul_compare") + (eq_attr "cpu" "ppca2")) + "nothing") + +;; FIXME: latency and multiplier reservation for 64-bit multiply? +(define_insn_reservation "ppca2-lmul" 6 + (and (eq_attr "type" "lmul,lmul_compare") + (eq_attr "cpu" "ppca2")) + "mult*3") + +;; D.4.9 +(define_insn_reservation "ppca2-idiv" 32 + (and (eq_attr "type" "idiv") + (eq_attr "cpu" "ppca2")) + "mult*32") + +(define_insn_reservation "ppca2-ldiv" 65 + (and (eq_attr "type" "ldiv") + (eq_attr "cpu" "ppca2")) + "mult*65") + +;; D.4.13 +(define_insn_reservation "ppca2-load" 5 + (and (eq_attr "type" "load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u") + (eq_attr "cpu" "ppca2")) + "nothing") + +;; D.8.1 +(define_insn_reservation "ppca2-fp" 6 + (and (eq_attr "type" "fp") ;; Ignore fpsimple insn types (SPE only). + (eq_attr "cpu" "ppca2")) + "axu") + +;; D.8.4 +(define_insn_reservation "ppca2-fp-load" 6 + (and (eq_attr "type" "fpload,fpload_u,fpload_ux") + (eq_attr "cpu" "ppca2")) + "axu") + +;; D.8.5 +(define_insn_reservation "ppca2-fp-store" 2 + (and (eq_attr "type" "fpstore,fpstore_u,fpstore_ux") + (eq_attr "cpu" "ppca2")) + "axu") + +;; D.8.6 +(define_insn_reservation "ppca2-fpcompare" 5 + (and (eq_attr "type" "fpcompare") + (eq_attr "cpu" "ppca2")) + "axu") + +;; D.8.7 +;; +;; Instructions from the same thread succeeding the floating-point +;; divide cannot be executed until the floating-point divide has +;; completed. Since there is nothing else we can do, this thread will +;; just have to stall. + +(define_insn_reservation "ppca2-ddiv" 72 + (and (eq_attr "type" "ddiv") + (eq_attr "cpu" "ppca2")) + "axu") + +(define_insn_reservation "ppca2-sdiv" 59 + (and (eq_attr "type" "sdiv") + (eq_attr "cpu" "ppca2")) + "axu") + +;; D.8.8 +;; +;; Instructions from the same thread succeeding the floating-point +;; divide cannot be executed until the floating-point divide has +;; completed. Since there is nothing else we can do, this thread will +;; just have to stall. + +(define_insn_reservation "ppca2-dsqrt" 69 + (and (eq_attr "type" "dsqrt") + (eq_attr "cpu" "ppca2")) + "axu") + +(define_insn_reservation "ppca2-ssqrt" 65 + (and (eq_attr "type" "ssqrt") + (eq_attr "cpu" "ppca2")) + "axu") diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md index 53b1054d200..6fbb7cdcdac 100644 --- a/gcc/config/rs6000/altivec.md +++ b/gcc/config/rs6000/altivec.md @@ -1,5 +1,5 @@ ;; AltiVec patterns. -;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 +;; Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 ;; Free Software Foundation, Inc. ;; Contributed by Aldy Hernandez (aldy@quesejoda.com) diff --git a/gcc/config/rs6000/cell.md b/gcc/config/rs6000/cell.md index 3fffd2740f9..dac9da94320 100644 --- a/gcc/config/rs6000/cell.md +++ b/gcc/config/rs6000/cell.md @@ -1,5 +1,5 @@ ;; Scheduling description for cell processor. -;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 +;; Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 ;; Free Software Foundation, Inc. ;; Contributed by Sony Computer Entertainment, Inc., @@ -157,7 +157,7 @@ ;; Integer latency is 2 cycles (define_insn_reservation "cell-integer" 2 (and (eq_attr "type" "integer,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "cell")) "slot01,fxu_cell") diff --git a/gcc/config/rs6000/e300c2c3.md b/gcc/config/rs6000/e300c2c3.md index 31bf14ce314..3462a209f74 100644 --- a/gcc/config/rs6000/e300c2c3.md +++ b/gcc/config/rs6000/e300c2c3.md @@ -1,5 +1,5 @@ ;; Pipeline description for Motorola PowerPC e300c3 core. -;; Copyright (C) 2008 Free Software Foundation, Inc. +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. ;; Contributed by Edmar Wienskoski (edmar@freescale.com) ;; ;; This file is part of GCC. @@ -90,7 +90,7 @@ ;; Other one cycle IU insns (define_insn_reservation "ppce300c3_iu" 1 - (and (eq_attr "type" "integer,insert_word") + (and (eq_attr "type" "integer,insert_word,isel") (ior (eq_attr "cpu" "ppce300c2") (eq_attr "cpu" "ppce300c3"))) "ppce300c3_decode,ppce300c3_issue+ppce300c3_iu_stage0+ppce300c3_retire") diff --git a/gcc/config/rs6000/e500mc.md b/gcc/config/rs6000/e500mc.md index 86434f95fe1..99a4b80ecf6 100644 --- a/gcc/config/rs6000/e500mc.md +++ b/gcc/config/rs6000/e500mc.md @@ -72,7 +72,7 @@ (define_insn_reservation "e500mc_su" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,cmp,compare,\ delayed_compare,var_delayed_compare,fast_compare,\ - shift,trap,var_shift_rotate,cntlz,exts") + shift,trap,var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "ppce500mc")) "e500mc_decode,e500mc_issue+e500mc_su_stage0+e500mc_retire") diff --git a/gcc/config/rs6000/mpc.md b/gcc/config/rs6000/mpc.md index a839f936648..415c6887232 100644 --- a/gcc/config/rs6000/mpc.md +++ b/gcc/config/rs6000/mpc.md @@ -1,5 +1,5 @@ ;; Scheduling description for Motorola PowerPC processor cores. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -43,7 +43,7 @@ (define_insn_reservation "mpccore-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "mpccore")) "iu_mpc") diff --git a/gcc/config/rs6000/option-defaults.h b/gcc/config/rs6000/option-defaults.h index 682add7605d..7e117d731da 100644 --- a/gcc/config/rs6000/option-defaults.h +++ b/gcc/config/rs6000/option-defaults.h @@ -50,15 +50,15 @@ /* Support for a compile-time default CPU, et cetera. The rules are: --with-cpu is ignored if -mcpu is specified; likewise --with-cpu-32 and --with-cpu-64. - --with-tune is ignored if -mtune is specified; likewise --with-tune-32 - and --with-tune-64. + --with-tune is ignored if -mtune or -mcpu is specified; likewise + --with-tune-32 and --with-tune-64. --with-float is ignored if -mhard-float or -msoft-float are - specified. */ + specified. */ #define OPTION_DEFAULT_SPECS \ + {"tune", "%{!mtune=*:%{!mcpu=*:-mtune=%(VALUE)}}" }, \ + {"tune_32", "%{" OPT_ARCH32 ":%{!mtune=*:%{!mcpu=*:-mtune=%(VALUE)}}}" }, \ + {"tune_64", "%{" OPT_ARCH64 ":%{!mtune=*:%{!mcpu=*:-mtune=%(VALUE)}}}" }, \ {"cpu", "%{!mcpu=*:-mcpu=%(VALUE)}" }, \ {"cpu_32", "%{" OPT_ARCH32 ":%{!mcpu=*:-mcpu=%(VALUE)}}" }, \ {"cpu_64", "%{" OPT_ARCH64 ":%{!mcpu=*:-mcpu=%(VALUE)}}" }, \ - {"tune", "%{!mtune=*:-mtune=%(VALUE)}" }, \ - {"tune_32", "%{" OPT_ARCH32 ":%{!mtune=*:-mtune=%(VALUE)}}" }, \ - {"tune_64", "%{" OPT_ARCH64 ":%{!mtune=*:-mtune=%(VALUE)}}" }, \ {"float", "%{!msoft-float:%{!mhard-float:-m%(VALUE)-float}}" } diff --git a/gcc/config/rs6000/power4.md b/gcc/config/rs6000/power4.md index 0214c98b139..60dbffd58c9 100644 --- a/gcc/config/rs6000/power4.md +++ b/gcc/config/rs6000/power4.md @@ -1,5 +1,5 @@ ;; Scheduling description for IBM Power4 and PowerPC 970 processors. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -188,7 +188,7 @@ ; Integer latency is 2 cycles (define_insn_reservation "power4-integer" 2 (and (eq_attr "type" "integer,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "power4")) "iq_power4") diff --git a/gcc/config/rs6000/power5.md b/gcc/config/rs6000/power5.md index 83ffabcfb3a..b6db0931219 100644 --- a/gcc/config/rs6000/power5.md +++ b/gcc/config/rs6000/power5.md @@ -1,5 +1,5 @@ ;; Scheduling description for IBM POWER5 processor. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; @@ -142,7 +142,7 @@ ; Integer latency is 2 cycles (define_insn_reservation "power5-integer" 2 (and (eq_attr "type" "integer,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "power5")) "iq_power5") diff --git a/gcc/config/rs6000/power6.md b/gcc/config/rs6000/power6.md index ba6524cfa65..8d54c812963 100644 --- a/gcc/config/rs6000/power6.md +++ b/gcc/config/rs6000/power6.md @@ -1,5 +1,5 @@ ;; Scheduling description for IBM POWER6 processor. -;; Copyright (C) 2006, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc. ;; Contributed by Peter Steinmetz (steinmtz@us.ibm.com) ;; ;; This file is part of GCC. @@ -201,6 +201,11 @@ (eq_attr "cpu" "power6")) "FXU_power6") +(define_insn_reservation "power6-isel" 1 + (and (eq_attr "type" "isel") + (eq_attr "cpu" "power6")) + "FXU_power6") + (define_insn_reservation "power6-exts" 1 (and (eq_attr "type" "exts") (eq_attr "cpu" "power6")) diff --git a/gcc/config/rs6000/power7.md b/gcc/config/rs6000/power7.md index 3b6a95e284e..148a7a52a8a 100644 --- a/gcc/config/rs6000/power7.md +++ b/gcc/config/rs6000/power7.md @@ -150,7 +150,7 @@ ; FX Unit (define_insn_reservation "power7-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,trap,\ - var_shift_rotate,exts") + var_shift_rotate,exts,isel") (eq_attr "cpu" "power7")) "DU_power7,FXU_power7") diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md index d03cce6f8a2..2d8a2a8d5d1 100644 --- a/gcc/config/rs6000/predicates.md +++ b/gcc/config/rs6000/predicates.md @@ -1,5 +1,5 @@ ;; Predicate definitions for POWER and PowerPC. -;; Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +;; Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. ;; diff --git a/gcc/config/rs6000/rios1.md b/gcc/config/rs6000/rios1.md index be2262d1281..9ad9ce3e161 100644 --- a/gcc/config/rs6000/rios1.md +++ b/gcc/config/rs6000/rios1.md @@ -1,5 +1,5 @@ ;; Scheduling description for IBM POWER processor. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -52,7 +52,7 @@ (define_insn_reservation "rios1-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,\ - trap,var_shift_rotate,cntlz,exts") + trap,var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "rios1,ppc601")) "iu_rios1") diff --git a/gcc/config/rs6000/rios2.md b/gcc/config/rs6000/rios2.md index 24fbc15b9ad..96633af2f8e 100644 --- a/gcc/config/rs6000/rios2.md +++ b/gcc/config/rs6000/rios2.md @@ -1,5 +1,5 @@ ;; Scheduling description for IBM Power2 processor. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -40,7 +40,7 @@ (define_insn_reservation "rios2-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "rios2")) "iu1_rios2|iu2_rios2") diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def new file mode 100644 index 00000000000..f5ad34882d4 --- /dev/null +++ b/gcc/config/rs6000/rs6000-builtin.def @@ -0,0 +1,990 @@ +/* Builtin functions for rs6000/powerpc. + Copyright (C) 2009 + Free Software Foundation, Inc. + Contributed by Michael Meissner (meissner@linux.vnet.ibm.com) + + 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 3, 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. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +/* Before including this file, two macros must be defined: + RS6000_BUILTIN -- 2 arguments, the enum name, and classification + RS6000_BUILTIN_EQUATE -- 2 arguments, enum name and value */ + +/* AltiVec builtins. */ +RS6000_BUILTIN(ALTIVEC_BUILTIN_ST_INTERNAL_4si, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LD_INTERNAL_4si, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ST_INTERNAL_8hi, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LD_INTERNAL_8hi, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ST_INTERNAL_16qi, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LD_INTERNAL_16qi, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ST_INTERNAL_4sf, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LD_INTERNAL_4sf, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUBM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUHM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUWM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDCUW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUBS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDSBS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDSHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDUWS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VADDSWS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VAND, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VANDC, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VAVGUB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VAVGSB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VAVGUH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VAVGSH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VAVGUW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VAVGSW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCFUX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCFSX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCTSXS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCTUXS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPBFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQUB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQUH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQUW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGEFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTUB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTSB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTUH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTSH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTUW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTSW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEXPTEFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VLOGEFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMADDFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMAXUB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMAXSB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMAXUH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMAXSH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMAXUW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMAXSW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMAXFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMHADDSHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMHRADDSHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMLADDUHM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMRGHB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMRGHH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMRGHW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMRGLB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMRGLH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMRGLW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMSUMUBM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMSUMMBM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMSUMUHM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMSUMSHM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMSUMUHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMSUMSHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMINUB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMINSB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMINUH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMINSH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMINUW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMINSW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMINFP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULEUB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULEUB_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULESB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULEUH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULEUH_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULESH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULOUB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULOUB_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULOSB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULOUH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULOUH_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VMULOSH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VNMSUBFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VNOR, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VOR, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_2DI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_4SI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_8HI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSEL_16QI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_2DI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_4SI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_8HI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPERM_16QI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKUHUM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKUWUM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKPX, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKUHSS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKSHSS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKUWSS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKSWSS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKUHUS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKSHUS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKUWUS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VPKSWUS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VREFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRFIM, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRFIN, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRFIP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRFIZ, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRLB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRLH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRLW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VRSQRTEFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSL, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLO, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSPLTB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSPLTH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSPLTW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSPLTISB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSPLTISH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSPLTISW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSRB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSRH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSRW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSRAB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSRAH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSRAW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSR, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSRO, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBUBM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBUHM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBUWM, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBFP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBCUW, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBUBS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBSBS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBUHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBSHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBUWS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUBSWS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUM4UBS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUM4SBS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUM4SHS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUM2SWS, RS6000_BTC_SAT) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSUMSWS, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VXOR, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLDOI_16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLDOI_8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLDOI_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VSLDOI_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VUPKHSB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VUPKHPX, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VUPKHSH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VUPKLSB, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VUPKLPX, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VUPKLSH, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_MTVSCR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_MFVSCR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_DSSALL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_DSS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVSL, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVSR, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_DSTT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_DSTST, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_DSTSTT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_DST, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVEBX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVEHX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVEWX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVXL, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVLX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVLXL, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVRX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_LVRXL, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVEBX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVEHX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVEWX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVXL, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVLX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVLXL, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVRX, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_STVRXL, RS6000_BTC_MEM) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPBFP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQFP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQUB_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQUH_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQUW_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGEFP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTFP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTSB_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTSH_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTSW_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTUB_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTUH_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGTUW_P, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ABSS_V4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ABSS_V8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ABSS_V16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ABS_V4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ABS_V4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ABS_V8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_ABS_V16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_MASK_FOR_LOAD, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_MASK_FOR_STORE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_INIT_V4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_INIT_V8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_INIT_V16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_INIT_V4SF, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SET_V4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SET_V8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SET_V16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SET_V4SF, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_EXT_V4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_EXT_V8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_EXT_V16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_EXT_V4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(ALTIVEC_BUILTIN_COPYSIGN_V4SF, RS6000_BTC_CONST) + +/* Altivec overloaded builtins. */ +/* For now, don't set the classification for overloaded functions. + The function should be converted to the type specific instruction + before we get to the point about classifying the builtin type. */ +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPEQ_P, RS6000_BTC_MISC) +RS6000_BUILTIN_EQUATE(ALTIVEC_BUILTIN_OVERLOADED_FIRST, + ALTIVEC_BUILTIN_VCMPEQ_P) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGT_P, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VCMPGE_P, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ABS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ABSS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ADD, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ADDC, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ADDS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_AND, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ANDC, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_AVG, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_EXTRACT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CEIL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPEQ, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPEQUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPEQUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPEQUW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPGE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPGT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPLE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CMPLT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_COPYSIGN, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CTF, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CTS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_CTU, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_DST, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_DSTST, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_DSTSTT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_DSTT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_EXPTE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_FLOOR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LD, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LDE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LDL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LOGE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVEBX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVEHX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVEWX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVLX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVLXL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVRX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVRXL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVSL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_LVSR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MADD, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MADDS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MAX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MERGEH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MERGEL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MIN, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MLADD, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MPERM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MRADDS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MRGHB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MRGHH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MRGHW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MRGLB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MRGLH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MRGLW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MSUM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MSUMS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MTVSCR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MULE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_MULO, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_NEARBYINT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_NMSUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_NOR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_OR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_PACK, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_PACKPX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_PACKS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_PACKSU, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_PERM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_RE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_RL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_RINT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ROUND, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_RSQRTE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SEL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SLD, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SLL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SLO, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLAT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLAT_S16, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLAT_S32, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLAT_S8, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLAT_U16, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLAT_U32, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLAT_U8, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLTB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLTH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLTW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SQRT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SRA, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SRL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SRO, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_ST, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STVEBX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STVEHX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STVEWX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STVLX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STVLXL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STVRX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STVRXL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SUBC, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SUBS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SUM2S, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SUM4S, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SUMS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_TRUNC, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_UNPACKH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_UNPACKL, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDFP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDSBS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDSHS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDSWS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDUBM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDUBS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDUHM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDUHS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDUWM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VADDUWS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VAVGSB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VAVGSH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VAVGSW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VAVGUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VAVGUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VAVGUW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCFSX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCFUX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPEQFP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPEQUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPEQUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPEQUW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPGTFP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPGTSB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPGTSH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPGTSW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPGTUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPGTUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VCMPGTUW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMAXFP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMAXSB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMAXSH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMAXSW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMAXUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMAXUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMAXUW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMINFP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMINSB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMINSH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMINSW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMINUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMINUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMINUW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMRGHB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMRGHH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMRGHW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMRGLB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMRGLH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMRGLW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMSUMMBM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMSUMSHM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMSUMSHS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMSUMUBM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMSUMUHM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMSUMUHS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULESB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULESH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULEUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULEUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULOSB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULOSH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULOUB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VMULOUH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKSHSS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKSHUS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKSWSS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKSWUS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKUHUM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKUHUS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKUWUM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VPKUWUS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VRLB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VRLH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VRLW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSLB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSLH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSLW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSPLTB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSPLTH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSPLTW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSRAB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSRAH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSRAW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSRB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSRH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSRW, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBFP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBSBS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBSHS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBSWS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBUBM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBUBS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBUHM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBUHS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBUWM, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUBUWS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUM4SBS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUM4SHS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VSUM4UBS, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VUPKHPX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VUPKHSB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VUPKHSH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VUPKLPX, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VUPKLSB, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_VUPKLSH, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_XOR, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_STEP, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_PROMOTE, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_INSERT, RS6000_BTC_MISC) +RS6000_BUILTIN(ALTIVEC_BUILTIN_VEC_SPLATS, RS6000_BTC_MISC) +RS6000_BUILTIN_EQUATE(ALTIVEC_BUILTIN_OVERLOADED_LAST, + ALTIVEC_BUILTIN_VEC_SPLATS) + +/* SPE builtins. */ +RS6000_BUILTIN(SPE_BUILTIN_EVADDW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVAND, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVANDC, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVDIVWS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVDIVWU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVEQV, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSADD, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSDIV, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSMUL, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSSUB, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLDDX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLDHX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLDWX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLHHESPLATX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLHHOSSPLATX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLHHOUSPLATX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHEX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHOSX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHOUX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHSPLATX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWWSPLATX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMERGEHI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMERGEHILO, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMERGELO, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMERGELOHI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEGSMFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEGSMFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEGSMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEGSMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEGUMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEGUMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMFAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMFANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESMIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESSF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESSFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESSFAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESSFANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHESSIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEUMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEUMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEUMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEUMIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEUSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHEUSIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOGSMFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOGSMFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOGSMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOGSMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOGUMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOGUMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMFAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMFANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSMIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSSF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSSFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSSFAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSSFANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOSSIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOUMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOUMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOUMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOUMIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOUSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMHOUSIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSSF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSSFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHUMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHUMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLSMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLSMIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLSSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLSSIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLUMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLUMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLUMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLUMIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLUSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWLUSIANW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSSFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSSF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSSFA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSSFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWSSFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWUMI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWUMIA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWUMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWUMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVNAND, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVNOR, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVOR, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVORC, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVRLW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSLW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSRWS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSRWU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTDDX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTDHX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTDWX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWHEX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWHOX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWWEX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWWOX, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSUBFW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVXOR, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVABS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVADDSMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVADDSSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVADDUMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVADDUSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVCNTLSW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVCNTLZW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVEXTSB, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVEXTSH, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSABS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCFSF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCFSI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCFUF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCFUI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCTSF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCTSI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCTSIZ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCTUF, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCTUI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCTUIZ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSNABS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSNEG, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMRA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVNEG, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVRNDW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSUBFSMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSUBFSSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSUBFUMIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSUBFUSIAAW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVADDIW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLDD, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLDH, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLDW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLHHESPLAT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLHHOSSPLAT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLHHOUSPLAT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHE, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHOS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHOU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWHSPLAT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVLWWSPLAT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVRLWI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSLWI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSRWIS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSRWIU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTDD, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTDH, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTDW, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWHE, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWHO, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWWE, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSTWWO, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSUBIFW, RS6000_BTC_MISC) + + /* Compares. */ +RS6000_BUILTIN(SPE_BUILTIN_EVCMPEQ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVCMPGTS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVCMPGTU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVCMPLTS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVCMPLTU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCMPEQ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCMPGT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSCMPLT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSTSTEQ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSTSTGT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVFSTSTLT, RS6000_BTC_MISC) + +/* EVSEL compares. */ +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_CMPEQ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_CMPGTS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_CMPGTU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_CMPLTS, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_CMPLTU, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_FSCMPEQ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_FSCMPGT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_FSCMPLT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_FSTSTEQ, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_FSTSTGT, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSEL_FSTSTLT, RS6000_BTC_MISC) + +RS6000_BUILTIN(SPE_BUILTIN_EVSPLATFI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVSPLATI, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSSMAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHUSIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHUMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSSFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSSIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHSMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHUSIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHUMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGSSFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGSMFAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGSMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGUMIAA, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGSSFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGSMFAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGSMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_EVMWHGUMIAN, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_MTSPEFSCR, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_MFSPEFSCR, RS6000_BTC_MISC) +RS6000_BUILTIN(SPE_BUILTIN_BRINC, RS6000_BTC_MISC) + +/* PAIRED builtins. */ +RS6000_BUILTIN(PAIRED_BUILTIN_DIVV2SF3, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_ABSV2SF2, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_NEGV2SF2, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_SQRTV2SF2, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_ADDV2SF3, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_SUBV2SF3, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_RESV2SF2, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MULV2SF3, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MSUB, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MADD, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_NMSUB, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_NMADD, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_NABSV2SF2, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_SUM0, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_SUM1, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MULS0, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MULS1, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MERGE00, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MERGE01, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MERGE10, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MERGE11, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MADDS0, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_MADDS1, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_STX, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_LX, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_SELV2SF4, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_CMPU0, RS6000_BTC_MISC) +RS6000_BUILTIN(PAIRED_BUILTIN_CMPU1, RS6000_BTC_MISC) + + /* VSX builtins. */ +RS6000_BUILTIN(VSX_BUILTIN_LXSDX, RS6000_BTC_MEM) +RS6000_BUILTIN(VSX_BUILTIN_LXVD2X, RS6000_BTC_MEM) +RS6000_BUILTIN(VSX_BUILTIN_LXVDSX, RS6000_BTC_MEM) +RS6000_BUILTIN(VSX_BUILTIN_LXVW4X, RS6000_BTC_MEM) +RS6000_BUILTIN(VSX_BUILTIN_STXSDX, RS6000_BTC_MEM) +RS6000_BUILTIN(VSX_BUILTIN_STXVD2X, RS6000_BTC_MEM) +RS6000_BUILTIN(VSX_BUILTIN_STXVW4X, RS6000_BTC_MEM) +RS6000_BUILTIN(VSX_BUILTIN_XSABSDP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XSADDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCMPODP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCMPUDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCPSGNDP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XSCVDPSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCVDPSXDS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCVDPSXWS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCVDPUXDS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCVDPUXWS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCVSPDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCVSXDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSCVUXDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSDIVDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMADDADP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMADDMDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMAXDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMINDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMOVDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMSUBADP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMSUBMDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSMULDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSNABSDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSNEGDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSNMADDADP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSNMADDMDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSNMSUBADP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSNMSUBMDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSRDPI, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSRDPIC, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSRDPIM, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSRDPIP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSRDPIZ, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSREDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSRSQRTEDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSSQRTDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSSUBDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_CPSGNDP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_CPSGNSP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XSTDIVDP_FE, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSTDIVDP_FG, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSTSQRTDP_FE, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XSTSQRTDP_FG, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVABSDP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XVABSSP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XVADDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVADDSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPEQDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPEQSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGEDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGESP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGTDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGTSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPEQDP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPEQSP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGEDP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGESP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGTDP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCMPGTSP_P, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCPSGNDP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XVCPSGNSP, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XVCVDPSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVDPSXDS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVDPSXWS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVDPUXDS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVDPUXDS_UNS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVDPUXWS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSPDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSPSXDS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSPSXWS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSPUXDS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSPUXWS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSXDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSXDSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSXWDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVSXWSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVUXDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVUXDDP_UNS, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVUXDSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVUXWDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVCVUXWSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVDIVDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVDIVSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMADDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMADDSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMAXDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMAXSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMINDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMINSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMSUBDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMSUBSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMULDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVMULSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNABSDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNABSSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNEGDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNEGSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNMADDDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNMADDSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNMSUBDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVNMSUBSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRDPI, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRDPIC, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRDPIM, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRDPIP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRDPIZ, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVREDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRESP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRSPI, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRSPIC, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRSPIM, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRSPIP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRSPIZ, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRSQRTEDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVRSQRTESP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVSQRTDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVSQRTSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVSUBDP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVSUBSP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTDIVDP_FE, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTDIVDP_FG, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTDIVSP_FE, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTDIVSP_FG, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTSQRTDP_FE, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTSQRTDP_FG, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTSQRTSP_FE, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XVTSQRTSP_FG, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_2DI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_4SI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_8HI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSEL_16QI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_2DI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_4SI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_8HI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VPERM_16QI_UNS, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXPERMDI_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXPERMDI_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXPERMDI_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXPERMDI_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXPERMDI_8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXPERMDI_16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_CONCAT_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_CONCAT_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_SET_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_SET_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_SPLAT_2DF, RS6000_BTC_PURE) +RS6000_BUILTIN(VSX_BUILTIN_SPLAT_2DI, RS6000_BTC_PURE) +RS6000_BUILTIN(VSX_BUILTIN_XXMRGHW_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXMRGHW_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXMRGLW_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXMRGLW_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSLDWI_16QI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSLDWI_8HI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSLDWI_4SI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSLDWI_4SF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSLDWI_2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_XXSLDWI_2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VEC_INIT_V2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VEC_INIT_V2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VEC_SET_V2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VEC_SET_V2DI, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VEC_EXT_V2DF, RS6000_BTC_CONST) +RS6000_BUILTIN(VSX_BUILTIN_VEC_EXT_V2DI, RS6000_BTC_CONST) + +/* VSX overloaded builtins, add the overloaded functions not present in + Altivec. */ +RS6000_BUILTIN(VSX_BUILTIN_VEC_MUL, RS6000_BTC_MISC) +RS6000_BUILTIN_EQUATE(VSX_BUILTIN_OVERLOADED_FIRST, + VSX_BUILTIN_VEC_MUL) +RS6000_BUILTIN(VSX_BUILTIN_VEC_MSUB, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_NMADD, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUITLIN_VEC_NMSUB, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_DIV, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_XXMRGHW, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_XXMRGLW, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_XXPERMDI, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_XXSLDWI, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_XXSPLTD, RS6000_BTC_MISC) +RS6000_BUILTIN(VSX_BUILTIN_VEC_XXSPLTW, RS6000_BTC_MISC) +RS6000_BUILTIN_EQUATE(VSX_BUILTIN_OVERLOADED_LAST, + VSX_BUILTIN_VEC_XXSPLTW) + +/* Combined VSX/Altivec builtins. */ +RS6000_BUILTIN(VECTOR_BUILTIN_FLOAT_V4SI_V4SF, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VECTOR_BUILTIN_UNSFLOAT_V4SI_V4SF, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VECTOR_BUILTIN_FIX_V4SF_V4SI, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(VECTOR_BUILTIN_FIXUNS_V4SF_V4SI, RS6000_BTC_FP_PURE) + +/* Power7 builtins, that aren't VSX instructions. */ +RS6000_BUILTIN(POWER7_BUILTIN_BPERMD, RS6000_BTC_CONST) + +/* Miscellaneous builtins. */ +RS6000_BUILTIN(RS6000_BUILTIN_RECIP, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(RS6000_BUILTIN_RECIPF, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(RS6000_BUILTIN_RSQRTF, RS6000_BTC_FP_PURE) +RS6000_BUILTIN(RS6000_BUILTIN_BSWAP_HI, RS6000_BTC_CONST) diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index cafe2b318aa..88649ea0735 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -130,6 +130,8 @@ typedef struct GTY(()) machine_function 64-bits wide and is allocated early enough so that the offset does not overflow the 16-bit load/store offset field. */ rtx sdmode_stack_slot; + /* True if any VSX or ALTIVEC vector type was used. */ + bool vsx_or_altivec_used_p; } machine_function; /* Target cpu type */ @@ -511,6 +513,25 @@ struct processor_costs ppc440_cost = { 1, /* streams */ }; +/* Instruction costs on PPC476 processors. */ +static const +struct processor_costs ppc476_cost = { + COSTS_N_INSNS (4), /* mulsi */ + COSTS_N_INSNS (4), /* mulsi_const */ + COSTS_N_INSNS (4), /* mulsi_const9 */ + COSTS_N_INSNS (4), /* muldi */ + COSTS_N_INSNS (11), /* divsi */ + COSTS_N_INSNS (11), /* divdi */ + COSTS_N_INSNS (6), /* fp */ + COSTS_N_INSNS (6), /* dmul */ + COSTS_N_INSNS (19), /* sdiv */ + COSTS_N_INSNS (33), /* ddiv */ + 32, /* l1 cache line size */ + 32, /* l1 cache */ + 512, /* l2 cache */ + 1, /* streams */ +}; + /* Instruction costs on PPC601 processors. */ static const struct processor_costs ppc601_cost = { @@ -797,6 +818,40 @@ struct processor_costs power7_cost = { 12, /* prefetch streams */ }; +/* Instruction costs on POWER A2 processors. */ +static const +struct processor_costs ppca2_cost = { + COSTS_N_INSNS (16), /* mulsi */ + COSTS_N_INSNS (16), /* mulsi_const */ + COSTS_N_INSNS (16), /* mulsi_const9 */ + COSTS_N_INSNS (16), /* muldi */ + COSTS_N_INSNS (22), /* divsi */ + COSTS_N_INSNS (28), /* divdi */ + COSTS_N_INSNS (3), /* fp */ + COSTS_N_INSNS (3), /* dmul */ + COSTS_N_INSNS (59), /* sdiv */ + COSTS_N_INSNS (72), /* ddiv */ + 64, + 16, /* l1 cache */ + 2048, /* l2 cache */ + 16, /* prefetch streams */ +}; + + +/* Table that classifies rs6000 builtin functions (pure, const, etc.). */ +#undef RS6000_BUILTIN +#undef RS6000_BUILTIN_EQUATE +#define RS6000_BUILTIN(NAME, TYPE) TYPE, +#define RS6000_BUILTIN_EQUATE(NAME, VALUE) + +static const enum rs6000_btc builtin_classify[(int)RS6000_BUILTIN_COUNT] = +{ +#include "rs6000-builtin.def" +}; + +#undef RS6000_BUILTIN +#undef RS6000_BUILTIN_EQUATE + static bool rs6000_function_ok_for_sibcall (tree, tree); static const char *rs6000_invalid_within_doloop (const_rtx); @@ -860,7 +915,7 @@ static void rs6000_elf_encode_section_info (tree, rtx, int) ATTRIBUTE_UNUSED; #endif static bool rs6000_use_blocks_for_constant_p (enum machine_mode, const_rtx); -static void rs6000_alloc_sdmode_stack_slot (void); +static void rs6000_expand_to_rtl_hook (void); static void rs6000_instantiate_decls (void); #if TARGET_XCOFF static void rs6000_xcoff_asm_output_anchor (rtx); @@ -928,6 +983,8 @@ static bool rs6000_builtin_support_vector_misalignment (enum static void def_builtin (int, const char *, tree, int); static bool rs6000_vector_alignment_reachable (const_tree, bool); static void rs6000_init_builtins (void); +static tree rs6000_builtin_decl (unsigned, bool); + static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx); static rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx); static rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx); @@ -984,7 +1041,6 @@ static void rs6000_init_dwarf_reg_sizes_extra (tree); static rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode); static rtx rs6000_debug_legitimize_address (rtx, rtx, enum machine_mode); static rtx rs6000_legitimize_tls_address (rtx, enum tls_model); -static rtx rs6000_delegitimize_address (rtx); static void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; static rtx rs6000_tls_get_addr (void); static rtx rs6000_got_sym (void); @@ -1314,6 +1370,8 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS rs6000_init_builtins +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL rs6000_builtin_decl #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin @@ -1445,14 +1503,11 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P #define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p -#undef TARGET_DELEGITIMIZE_ADDRESS -#define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address - #undef TARGET_BUILTIN_RECIPROCAL #define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal #undef TARGET_EXPAND_TO_RTL_HOOK -#define TARGET_EXPAND_TO_RTL_HOOK rs6000_alloc_sdmode_stack_slot +#define TARGET_EXPAND_TO_RTL_HOOK rs6000_expand_to_rtl_hook #undef TARGET_INSTANTIATE_DECLS #define TARGET_INSTANTIATE_DECLS rs6000_instantiate_decls @@ -2125,6 +2180,12 @@ rs6000_override_options (const char *default_cpu) POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, {"464fp", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, + {"476", PROCESSOR_PPC476, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_PPC_GFXOPT | MASK_MFCRF + | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB}, + {"476fp", PROCESSOR_PPC476, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POPCNTB + | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB}, {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK}, {"601", PROCESSOR_PPC601, MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING}, @@ -2149,6 +2210,9 @@ rs6000_override_options (const char *default_cpu) /* 8548 has a dummy entry for now. */ {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN | MASK_ISEL}, + {"a2", PROCESSOR_PPCA2, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_POPCNTB + | MASK_CMPB | MASK_NO_UPDATE }, {"e300c2", PROCESSOR_PPCE300C2, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, {"e300c3", PROCESSOR_PPCE300C3, POWERPC_BASE_MASK}, {"e500mc", PROCESSOR_PPCE500MC, POWERPC_BASE_MASK | MASK_PPC_GFXOPT @@ -2216,9 +2280,16 @@ rs6000_override_options (const char *default_cpu) | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW | MASK_DLMZB | MASK_CMPB | MASK_MFPGPR | MASK_DFP - | MASK_POPCNTD | MASK_VSX | MASK_ISEL) + | MASK_POPCNTD | MASK_VSX | MASK_ISEL | MASK_NO_UPDATE) }; + /* Numerous experiment shows that IRA based loop pressure + calculation works better for RTL loop invariant motion on targets + with enough (>= 32) registers. It is an expensive optimization. + So it is on only for peak performance. */ + if (optimize >= 3) + flag_ira_loop_pressure = 1; + /* Set the pointer size. */ if (TARGET_64BIT) { @@ -2495,6 +2566,7 @@ rs6000_override_options (const char *default_cpu) && rs6000_cpu != PROCESSOR_POWER5 && rs6000_cpu != PROCESSOR_POWER6 && rs6000_cpu != PROCESSOR_POWER7 + && rs6000_cpu != PROCESSOR_PPCA2 && rs6000_cpu != PROCESSOR_CELL); rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4 || rs6000_cpu == PROCESSOR_POWER5 @@ -2650,6 +2722,10 @@ rs6000_override_options (const char *default_cpu) rs6000_cost = &ppc440_cost; break; + case PROCESSOR_PPC476: + rs6000_cost = &ppc476_cost; + break; + case PROCESSOR_PPC601: rs6000_cost = &ppc601_cost; break; @@ -2713,6 +2789,10 @@ rs6000_override_options (const char *default_cpu) rs6000_cost = &power7_cost; break; + case PROCESSOR_PPCA2: + rs6000_cost = &ppca2_cost; + break; + default: gcc_unreachable (); } @@ -5128,33 +5208,6 @@ rs6000_debug_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) return ret; } -/* If ORIG_X is a constant pool reference, return its known value, - otherwise ORIG_X. */ - -static rtx -rs6000_delegitimize_address (rtx x) -{ - rtx orig_x = delegitimize_mem_from_attrs (x); - - x = orig_x; - - if (!MEM_P (x)) - return orig_x; - - x = XEXP (x, 0); - - if (legitimate_constant_pool_address_p (x) - && GET_CODE (XEXP (x, 1)) == CONST - && GET_CODE (XEXP (XEXP (x, 1), 0)) == MINUS - && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == SYMBOL_REF - && constant_pool_expr_p (XEXP (XEXP (XEXP (x, 1), 0), 0)) - && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == SYMBOL_REF - && toc_relative_expr_p (XEXP (XEXP (XEXP (x, 1), 0), 1))) - return get_pool_constant (XEXP (XEXP (XEXP (x, 1), 0), 0)); - - return orig_x; -} - /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. We need to emit DTP-relative relocations. */ @@ -8465,13 +8518,54 @@ def_builtin (int mask, const char *name, tree type, int code) { if ((mask & target_flags) || TARGET_PAIRED_FLOAT) { + tree t; if (rs6000_builtin_decls[code]) fatal_error ("internal error: builtin function to %s already processed.", name); - rs6000_builtin_decls[code] = + rs6000_builtin_decls[code] = t = add_builtin_function (name, type, code, BUILT_IN_MD, NULL, NULL_TREE); + + gcc_assert (code >= 0 && code < (int)RS6000_BUILTIN_COUNT); + switch (builtin_classify[code]) + { + default: + gcc_unreachable (); + + /* assume builtin can do anything. */ + case RS6000_BTC_MISC: + break; + + /* const function, function only depends on the inputs. */ + case RS6000_BTC_CONST: + TREE_READONLY (t) = 1; + TREE_NOTHROW (t) = 1; + break; + + /* pure function, function can read global memory. */ + case RS6000_BTC_PURE: + DECL_PURE_P (t) = 1; + TREE_NOTHROW (t) = 1; + break; + + /* Function is a math function. If rounding mode is on, then treat + the function as not reading global memory, but it can have + arbitrary side effects. If it is off, then assume the function is + a const function. This mimics the ATTR_MATHFN_FPROUNDING + attribute in builtin-attribute.def that is used for the math + functions. */ + case RS6000_BTC_FP_PURE: + TREE_NOTHROW (t) = 1; + if (flag_rounding_math) + { + DECL_PURE_P (t) = 1; + DECL_IS_NOVOPS (t) = 1; + } + else + TREE_READONLY (t) = 1; + break; + } } } @@ -11148,6 +11242,17 @@ rs6000_init_builtins (void) #endif } +/* Returns the rs6000 builtin decl for CODE. */ + +static tree +rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= RS6000_BUILTIN_COUNT) + return error_mark_node; + + return rs6000_builtin_decls[code]; +} + /* Search through a set of builtins and enable the mask bits. DESC is an array of builtins. SIZE is the total number of builtins. @@ -13087,6 +13192,38 @@ rs6000_check_sdmode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) return NULL_TREE; } +static tree +rs6000_check_vector_mode (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) +{ + /* Don't walk into types. */ + if (*tp == NULL_TREE || *tp == error_mark_node || TYPE_P (*tp)) + { + *walk_subtrees = 0; + return NULL_TREE; + } + + switch (TREE_CODE (*tp)) + { + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case RESULT_DECL: + case SSA_NAME: + case REAL_CST: + case INDIRECT_REF: + case ALIGN_INDIRECT_REF: + case MISALIGNED_INDIRECT_REF: + case VIEW_CONVERT_EXPR: + if (VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (*tp)))) + return *tp; + break; + default: + break; + } + + return NULL_TREE; +} + enum reload_reg_type { GPR_REGISTER_TYPE, VECTOR_REGISTER_TYPE, @@ -13527,11 +13664,17 @@ rs6000_ira_cover_classes (void) return (TARGET_VSX) ? cover_vsx : cover_pre_vsx; } -/* Allocate a 64-bit stack slot to be used for copying SDmode - values through if this function has any SDmode references. */ +/* Scan the trees looking for certain types. + + Allocate a 64-bit stack slot to be used for copying SDmode values through if + this function has any SDmode references. + + If VSX, note whether any vector operation was done so we can set VRSAVE to + non-zero, even if we just use the floating point registers to tell the + kernel to save the vector registers. */ static void -rs6000_alloc_sdmode_stack_slot (void) +rs6000_expand_to_rtl_hook (void) { tree t; basic_block bb; @@ -13539,6 +13682,24 @@ rs6000_alloc_sdmode_stack_slot (void) gcc_assert (cfun->machine->sdmode_stack_slot == NULL_RTX); + /* Check for vectors. */ + if (TARGET_VSX) + { + FOR_EACH_BB (bb) + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + if (walk_gimple_op (gsi_stmt (gsi), rs6000_check_vector_mode, + NULL)) + { + cfun->machine->vsx_or_altivec_used_p = true; + goto found_vector; + } + } + found_vector: + ; + } + + /* Check for SDmode being used. */ FOR_EACH_BB (bb) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -16680,6 +16841,15 @@ compute_vrsave_mask (void) if (df_regs_ever_live_p (i)) mask |= ALTIVEC_REG_BIT (i); + /* If VSX is used, we might have used a traditional floating point register + in a vector mode without using any altivec registers. However the VRSAVE + register does not have room to indicate the floating point registers. + Modern kernels only look to see if the value is non-zero to determine if + they need to save the vector registers, so we just set an arbitrary + value if any vector type was used. */ + if (mask == 0 && TARGET_VSX && cfun->machine->vsx_or_altivec_used_p) + mask = 0xFFF; + if (mask == 0) return mask; @@ -20052,8 +20222,10 @@ rs6000_output_function_epilogue (FILE *file, use language_string. C is 0. Fortran is 1. Pascal is 2. Ada is 3. C++ is 9. Java is 13. Objective-C is 14. Objective-C++ isn't assigned - a number, so for now use 9. */ - if (! strcmp (language_string, "GNU C")) + a number, so for now use 9. LTO isn't assigned a number either, + so for now use 0. */ + if (! strcmp (language_string, "GNU C") + || ! strcmp (language_string, "GNU GIMPLE")) i = 0; else if (! strcmp (language_string, "GNU F77") || ! strcmp (language_string, "GNU Fortran")) @@ -21782,6 +21954,7 @@ rs6000_issue_rate (void) case CPU_PPCE500MC: return 2; case CPU_RIOS2: + case CPU_PPC476: case CPU_PPC604: case CPU_PPC604E: case CPU_PPC620: diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 52d9a594be2..4b1ca3d635a 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -83,6 +83,12 @@ #define ASM_CPU_POWER7_SPEC "-mpower4 -maltivec" #endif +#ifdef HAVE_AS_DCI +#define ASM_CPU_476_SPEC "-m476" +#else +#define ASM_CPU_476_SPEC "-mpower4" +#endif + /* Common ASM definitions used by ASM_SPEC among the various targets for handling -mcpu=xxx switches. There is a parallel list in driver-rs6000.c to provide the default assembler options if the user uses -mcpu=native, so if @@ -107,6 +113,7 @@ %{mcpu=power6: %(asm_cpu_power6) -maltivec} \ %{mcpu=power6x: %(asm_cpu_power6) -maltivec} \ %{mcpu=power7: %(asm_cpu_power7)} \ +%{mcpu=a2: -ma2} \ %{mcpu=powerpc: -mppc} \ %{mcpu=rios: -mpwr} \ %{mcpu=rios1: -mpwr} \ @@ -122,6 +129,8 @@ %{mcpu=440fp: -m440} \ %{mcpu=464: -m440} \ %{mcpu=464fp: -m440} \ +%{mcpu=476: %(asm_cpu_476)} \ +%{mcpu=476fp: %(asm_cpu_476)} \ %{mcpu=505: -mppc} \ %{mcpu=601: -m601} \ %{mcpu=602: -mppc} \ @@ -177,6 +186,7 @@ { "asm_cpu_power5", ASM_CPU_POWER5_SPEC }, \ { "asm_cpu_power6", ASM_CPU_POWER6_SPEC }, \ { "asm_cpu_power7", ASM_CPU_POWER7_SPEC }, \ + { "asm_cpu_476", ASM_CPU_476_SPEC }, \ SUBTARGET_EXTRA_SPECS /* -mcpu=native handling only makes sense with compiler running on @@ -317,6 +327,7 @@ enum processor_type PROCESSOR_PPC403, PROCESSOR_PPC405, PROCESSOR_PPC440, + PROCESSOR_PPC476, PROCESSOR_PPC601, PROCESSOR_PPC603, PROCESSOR_PPC604, @@ -334,7 +345,8 @@ enum processor_type PROCESSOR_POWER5, PROCESSOR_POWER6, PROCESSOR_POWER7, - PROCESSOR_CELL + PROCESSOR_CELL, + PROCESSOR_PPCA2 }; /* FPU operations supported. @@ -1021,10 +1033,12 @@ extern unsigned rs6000_pointer_size; #define HARD_REGNO_NREGS(REGNO, MODE) rs6000_hard_regno_nregs[(MODE)][(REGNO)] -#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) \ - ((TARGET_32BIT && TARGET_POWERPC64 \ - && (GET_MODE_SIZE (MODE) > 4) \ - && INT_REGNO_P (REGNO)) ? 1 : 0) +#define HARD_REGNO_CALL_PART_CLOBBERED(REGNO, MODE) \ + (((TARGET_32BIT && TARGET_POWERPC64 \ + && (GET_MODE_SIZE (MODE) > 4) \ + && INT_REGNO_P (REGNO)) ? 1 : 0) \ + || (TARGET_VSX && FP_REGNO_P (REGNO) \ + && GET_MODE_SIZE (MODE) > 8)) #define VSX_VECTOR_MODE(MODE) \ ((MODE) == V4SFmode \ @@ -2412,964 +2426,35 @@ extern int optimize; extern int flag_expensive_optimizations; extern int frame_pointer_needed; +/* Classification of the builtin functions to properly set the declaration tree + flags. */ +enum rs6000_btc +{ + RS6000_BTC_MISC, /* assume builtin can do anything */ + RS6000_BTC_CONST, /* builtin is a 'const' function. */ + RS6000_BTC_PURE, /* builtin is a 'pure' function. */ + RS6000_BTC_FP_PURE /* builtin is 'pure' if rounding math. */ +}; + +/* Convenience macros to document the instruction type. */ +#define RS6000_BTC_MEM RS6000_BTC_MISC /* load/store touches memory */ +#define RS6000_BTC_SAT RS6000_BTC_MISC /* VMX saturate sets VSCR register */ + +#undef RS6000_BUILTIN +#undef RS6000_BUILTIN_EQUATE +#define RS6000_BUILTIN(NAME, TYPE) NAME, +#define RS6000_BUILTIN_EQUATE(NAME, VALUE) NAME = VALUE, + enum rs6000_builtins { - /* AltiVec builtins. */ - ALTIVEC_BUILTIN_ST_INTERNAL_4si, - ALTIVEC_BUILTIN_LD_INTERNAL_4si, - ALTIVEC_BUILTIN_ST_INTERNAL_8hi, - ALTIVEC_BUILTIN_LD_INTERNAL_8hi, - ALTIVEC_BUILTIN_ST_INTERNAL_16qi, - ALTIVEC_BUILTIN_LD_INTERNAL_16qi, - ALTIVEC_BUILTIN_ST_INTERNAL_4sf, - ALTIVEC_BUILTIN_LD_INTERNAL_4sf, - ALTIVEC_BUILTIN_VADDUBM, - ALTIVEC_BUILTIN_VADDUHM, - ALTIVEC_BUILTIN_VADDUWM, - ALTIVEC_BUILTIN_VADDFP, - ALTIVEC_BUILTIN_VADDCUW, - ALTIVEC_BUILTIN_VADDUBS, - ALTIVEC_BUILTIN_VADDSBS, - ALTIVEC_BUILTIN_VADDUHS, - ALTIVEC_BUILTIN_VADDSHS, - ALTIVEC_BUILTIN_VADDUWS, - ALTIVEC_BUILTIN_VADDSWS, - ALTIVEC_BUILTIN_VAND, - ALTIVEC_BUILTIN_VANDC, - ALTIVEC_BUILTIN_VAVGUB, - ALTIVEC_BUILTIN_VAVGSB, - ALTIVEC_BUILTIN_VAVGUH, - ALTIVEC_BUILTIN_VAVGSH, - ALTIVEC_BUILTIN_VAVGUW, - ALTIVEC_BUILTIN_VAVGSW, - ALTIVEC_BUILTIN_VCFUX, - ALTIVEC_BUILTIN_VCFSX, - ALTIVEC_BUILTIN_VCTSXS, - ALTIVEC_BUILTIN_VCTUXS, - ALTIVEC_BUILTIN_VCMPBFP, - ALTIVEC_BUILTIN_VCMPEQUB, - ALTIVEC_BUILTIN_VCMPEQUH, - ALTIVEC_BUILTIN_VCMPEQUW, - ALTIVEC_BUILTIN_VCMPEQFP, - ALTIVEC_BUILTIN_VCMPGEFP, - ALTIVEC_BUILTIN_VCMPGTUB, - ALTIVEC_BUILTIN_VCMPGTSB, - ALTIVEC_BUILTIN_VCMPGTUH, - ALTIVEC_BUILTIN_VCMPGTSH, - ALTIVEC_BUILTIN_VCMPGTUW, - ALTIVEC_BUILTIN_VCMPGTSW, - ALTIVEC_BUILTIN_VCMPGTFP, - ALTIVEC_BUILTIN_VEXPTEFP, - ALTIVEC_BUILTIN_VLOGEFP, - ALTIVEC_BUILTIN_VMADDFP, - ALTIVEC_BUILTIN_VMAXUB, - ALTIVEC_BUILTIN_VMAXSB, - ALTIVEC_BUILTIN_VMAXUH, - ALTIVEC_BUILTIN_VMAXSH, - ALTIVEC_BUILTIN_VMAXUW, - ALTIVEC_BUILTIN_VMAXSW, - ALTIVEC_BUILTIN_VMAXFP, - ALTIVEC_BUILTIN_VMHADDSHS, - ALTIVEC_BUILTIN_VMHRADDSHS, - ALTIVEC_BUILTIN_VMLADDUHM, - ALTIVEC_BUILTIN_VMRGHB, - ALTIVEC_BUILTIN_VMRGHH, - ALTIVEC_BUILTIN_VMRGHW, - ALTIVEC_BUILTIN_VMRGLB, - ALTIVEC_BUILTIN_VMRGLH, - ALTIVEC_BUILTIN_VMRGLW, - ALTIVEC_BUILTIN_VMSUMUBM, - ALTIVEC_BUILTIN_VMSUMMBM, - ALTIVEC_BUILTIN_VMSUMUHM, - ALTIVEC_BUILTIN_VMSUMSHM, - ALTIVEC_BUILTIN_VMSUMUHS, - ALTIVEC_BUILTIN_VMSUMSHS, - ALTIVEC_BUILTIN_VMINUB, - ALTIVEC_BUILTIN_VMINSB, - ALTIVEC_BUILTIN_VMINUH, - ALTIVEC_BUILTIN_VMINSH, - ALTIVEC_BUILTIN_VMINUW, - ALTIVEC_BUILTIN_VMINSW, - ALTIVEC_BUILTIN_VMINFP, - ALTIVEC_BUILTIN_VMULEUB, - ALTIVEC_BUILTIN_VMULEUB_UNS, - ALTIVEC_BUILTIN_VMULESB, - ALTIVEC_BUILTIN_VMULEUH, - ALTIVEC_BUILTIN_VMULEUH_UNS, - ALTIVEC_BUILTIN_VMULESH, - ALTIVEC_BUILTIN_VMULOUB, - ALTIVEC_BUILTIN_VMULOUB_UNS, - ALTIVEC_BUILTIN_VMULOSB, - ALTIVEC_BUILTIN_VMULOUH, - ALTIVEC_BUILTIN_VMULOUH_UNS, - ALTIVEC_BUILTIN_VMULOSH, - ALTIVEC_BUILTIN_VNMSUBFP, - ALTIVEC_BUILTIN_VNOR, - ALTIVEC_BUILTIN_VOR, - ALTIVEC_BUILTIN_VSEL_2DF, /* needed for VSX */ - ALTIVEC_BUILTIN_VSEL_2DI, /* needed for VSX */ - ALTIVEC_BUILTIN_VSEL_4SI, - ALTIVEC_BUILTIN_VSEL_4SF, - ALTIVEC_BUILTIN_VSEL_8HI, - ALTIVEC_BUILTIN_VSEL_16QI, - ALTIVEC_BUILTIN_VSEL_2DI_UNS, - ALTIVEC_BUILTIN_VSEL_4SI_UNS, - ALTIVEC_BUILTIN_VSEL_8HI_UNS, - ALTIVEC_BUILTIN_VSEL_16QI_UNS, - ALTIVEC_BUILTIN_VPERM_2DF, /* needed for VSX */ - ALTIVEC_BUILTIN_VPERM_2DI, /* needed for VSX */ - ALTIVEC_BUILTIN_VPERM_4SI, - ALTIVEC_BUILTIN_VPERM_4SF, - ALTIVEC_BUILTIN_VPERM_8HI, - ALTIVEC_BUILTIN_VPERM_16QI, - ALTIVEC_BUILTIN_VPERM_2DI_UNS, - ALTIVEC_BUILTIN_VPERM_4SI_UNS, - ALTIVEC_BUILTIN_VPERM_8HI_UNS, - ALTIVEC_BUILTIN_VPERM_16QI_UNS, - ALTIVEC_BUILTIN_VPKUHUM, - ALTIVEC_BUILTIN_VPKUWUM, - ALTIVEC_BUILTIN_VPKPX, - ALTIVEC_BUILTIN_VPKUHSS, - ALTIVEC_BUILTIN_VPKSHSS, - ALTIVEC_BUILTIN_VPKUWSS, - ALTIVEC_BUILTIN_VPKSWSS, - ALTIVEC_BUILTIN_VPKUHUS, - ALTIVEC_BUILTIN_VPKSHUS, - ALTIVEC_BUILTIN_VPKUWUS, - ALTIVEC_BUILTIN_VPKSWUS, - ALTIVEC_BUILTIN_VREFP, - ALTIVEC_BUILTIN_VRFIM, - ALTIVEC_BUILTIN_VRFIN, - ALTIVEC_BUILTIN_VRFIP, - ALTIVEC_BUILTIN_VRFIZ, - ALTIVEC_BUILTIN_VRLB, - ALTIVEC_BUILTIN_VRLH, - ALTIVEC_BUILTIN_VRLW, - ALTIVEC_BUILTIN_VRSQRTEFP, - ALTIVEC_BUILTIN_VSLB, - ALTIVEC_BUILTIN_VSLH, - ALTIVEC_BUILTIN_VSLW, - ALTIVEC_BUILTIN_VSL, - ALTIVEC_BUILTIN_VSLO, - ALTIVEC_BUILTIN_VSPLTB, - ALTIVEC_BUILTIN_VSPLTH, - ALTIVEC_BUILTIN_VSPLTW, - ALTIVEC_BUILTIN_VSPLTISB, - ALTIVEC_BUILTIN_VSPLTISH, - ALTIVEC_BUILTIN_VSPLTISW, - ALTIVEC_BUILTIN_VSRB, - ALTIVEC_BUILTIN_VSRH, - ALTIVEC_BUILTIN_VSRW, - ALTIVEC_BUILTIN_VSRAB, - ALTIVEC_BUILTIN_VSRAH, - ALTIVEC_BUILTIN_VSRAW, - ALTIVEC_BUILTIN_VSR, - ALTIVEC_BUILTIN_VSRO, - ALTIVEC_BUILTIN_VSUBUBM, - ALTIVEC_BUILTIN_VSUBUHM, - ALTIVEC_BUILTIN_VSUBUWM, - ALTIVEC_BUILTIN_VSUBFP, - ALTIVEC_BUILTIN_VSUBCUW, - ALTIVEC_BUILTIN_VSUBUBS, - ALTIVEC_BUILTIN_VSUBSBS, - ALTIVEC_BUILTIN_VSUBUHS, - ALTIVEC_BUILTIN_VSUBSHS, - ALTIVEC_BUILTIN_VSUBUWS, - ALTIVEC_BUILTIN_VSUBSWS, - ALTIVEC_BUILTIN_VSUM4UBS, - ALTIVEC_BUILTIN_VSUM4SBS, - ALTIVEC_BUILTIN_VSUM4SHS, - ALTIVEC_BUILTIN_VSUM2SWS, - ALTIVEC_BUILTIN_VSUMSWS, - ALTIVEC_BUILTIN_VXOR, - ALTIVEC_BUILTIN_VSLDOI_16QI, - ALTIVEC_BUILTIN_VSLDOI_8HI, - ALTIVEC_BUILTIN_VSLDOI_4SI, - ALTIVEC_BUILTIN_VSLDOI_4SF, - ALTIVEC_BUILTIN_VUPKHSB, - ALTIVEC_BUILTIN_VUPKHPX, - ALTIVEC_BUILTIN_VUPKHSH, - ALTIVEC_BUILTIN_VUPKLSB, - ALTIVEC_BUILTIN_VUPKLPX, - ALTIVEC_BUILTIN_VUPKLSH, - ALTIVEC_BUILTIN_MTVSCR, - ALTIVEC_BUILTIN_MFVSCR, - ALTIVEC_BUILTIN_DSSALL, - ALTIVEC_BUILTIN_DSS, - ALTIVEC_BUILTIN_LVSL, - ALTIVEC_BUILTIN_LVSR, - ALTIVEC_BUILTIN_DSTT, - ALTIVEC_BUILTIN_DSTST, - ALTIVEC_BUILTIN_DSTSTT, - ALTIVEC_BUILTIN_DST, - ALTIVEC_BUILTIN_LVEBX, - ALTIVEC_BUILTIN_LVEHX, - ALTIVEC_BUILTIN_LVEWX, - ALTIVEC_BUILTIN_LVXL, - ALTIVEC_BUILTIN_LVX, - ALTIVEC_BUILTIN_STVX, - ALTIVEC_BUILTIN_LVLX, - ALTIVEC_BUILTIN_LVLXL, - ALTIVEC_BUILTIN_LVRX, - ALTIVEC_BUILTIN_LVRXL, - ALTIVEC_BUILTIN_STVEBX, - ALTIVEC_BUILTIN_STVEHX, - ALTIVEC_BUILTIN_STVEWX, - ALTIVEC_BUILTIN_STVXL, - ALTIVEC_BUILTIN_STVLX, - ALTIVEC_BUILTIN_STVLXL, - ALTIVEC_BUILTIN_STVRX, - ALTIVEC_BUILTIN_STVRXL, - ALTIVEC_BUILTIN_VCMPBFP_P, - ALTIVEC_BUILTIN_VCMPEQFP_P, - ALTIVEC_BUILTIN_VCMPEQUB_P, - ALTIVEC_BUILTIN_VCMPEQUH_P, - ALTIVEC_BUILTIN_VCMPEQUW_P, - ALTIVEC_BUILTIN_VCMPGEFP_P, - ALTIVEC_BUILTIN_VCMPGTFP_P, - ALTIVEC_BUILTIN_VCMPGTSB_P, - ALTIVEC_BUILTIN_VCMPGTSH_P, - ALTIVEC_BUILTIN_VCMPGTSW_P, - ALTIVEC_BUILTIN_VCMPGTUB_P, - ALTIVEC_BUILTIN_VCMPGTUH_P, - ALTIVEC_BUILTIN_VCMPGTUW_P, - ALTIVEC_BUILTIN_ABSS_V4SI, - ALTIVEC_BUILTIN_ABSS_V8HI, - ALTIVEC_BUILTIN_ABSS_V16QI, - ALTIVEC_BUILTIN_ABS_V4SI, - ALTIVEC_BUILTIN_ABS_V4SF, - ALTIVEC_BUILTIN_ABS_V8HI, - ALTIVEC_BUILTIN_ABS_V16QI, - ALTIVEC_BUILTIN_MASK_FOR_LOAD, - ALTIVEC_BUILTIN_MASK_FOR_STORE, - ALTIVEC_BUILTIN_VEC_INIT_V4SI, - ALTIVEC_BUILTIN_VEC_INIT_V8HI, - ALTIVEC_BUILTIN_VEC_INIT_V16QI, - ALTIVEC_BUILTIN_VEC_INIT_V4SF, - ALTIVEC_BUILTIN_VEC_SET_V4SI, - ALTIVEC_BUILTIN_VEC_SET_V8HI, - ALTIVEC_BUILTIN_VEC_SET_V16QI, - ALTIVEC_BUILTIN_VEC_SET_V4SF, - ALTIVEC_BUILTIN_VEC_EXT_V4SI, - ALTIVEC_BUILTIN_VEC_EXT_V8HI, - ALTIVEC_BUILTIN_VEC_EXT_V16QI, - ALTIVEC_BUILTIN_VEC_EXT_V4SF, - ALTIVEC_BUILTIN_COPYSIGN_V4SF, - - /* Altivec overloaded builtins. */ - ALTIVEC_BUILTIN_VCMPEQ_P, - ALTIVEC_BUILTIN_OVERLOADED_FIRST = ALTIVEC_BUILTIN_VCMPEQ_P, - ALTIVEC_BUILTIN_VCMPGT_P, - ALTIVEC_BUILTIN_VCMPGE_P, - ALTIVEC_BUILTIN_VEC_ABS, - ALTIVEC_BUILTIN_VEC_ABSS, - ALTIVEC_BUILTIN_VEC_ADD, - ALTIVEC_BUILTIN_VEC_ADDC, - ALTIVEC_BUILTIN_VEC_ADDS, - ALTIVEC_BUILTIN_VEC_AND, - ALTIVEC_BUILTIN_VEC_ANDC, - ALTIVEC_BUILTIN_VEC_AVG, - ALTIVEC_BUILTIN_VEC_EXTRACT, - ALTIVEC_BUILTIN_VEC_CEIL, - ALTIVEC_BUILTIN_VEC_CMPB, - ALTIVEC_BUILTIN_VEC_CMPEQ, - ALTIVEC_BUILTIN_VEC_CMPEQUB, - ALTIVEC_BUILTIN_VEC_CMPEQUH, - ALTIVEC_BUILTIN_VEC_CMPEQUW, - ALTIVEC_BUILTIN_VEC_CMPGE, - ALTIVEC_BUILTIN_VEC_CMPGT, - ALTIVEC_BUILTIN_VEC_CMPLE, - ALTIVEC_BUILTIN_VEC_CMPLT, - ALTIVEC_BUILTIN_VEC_COPYSIGN, - ALTIVEC_BUILTIN_VEC_CTF, - ALTIVEC_BUILTIN_VEC_CTS, - ALTIVEC_BUILTIN_VEC_CTU, - ALTIVEC_BUILTIN_VEC_DST, - ALTIVEC_BUILTIN_VEC_DSTST, - ALTIVEC_BUILTIN_VEC_DSTSTT, - ALTIVEC_BUILTIN_VEC_DSTT, - ALTIVEC_BUILTIN_VEC_EXPTE, - ALTIVEC_BUILTIN_VEC_FLOOR, - ALTIVEC_BUILTIN_VEC_LD, - ALTIVEC_BUILTIN_VEC_LDE, - ALTIVEC_BUILTIN_VEC_LDL, - ALTIVEC_BUILTIN_VEC_LOGE, - ALTIVEC_BUILTIN_VEC_LVEBX, - ALTIVEC_BUILTIN_VEC_LVEHX, - ALTIVEC_BUILTIN_VEC_LVEWX, - ALTIVEC_BUILTIN_VEC_LVLX, - ALTIVEC_BUILTIN_VEC_LVLXL, - ALTIVEC_BUILTIN_VEC_LVRX, - ALTIVEC_BUILTIN_VEC_LVRXL, - ALTIVEC_BUILTIN_VEC_LVSL, - ALTIVEC_BUILTIN_VEC_LVSR, - ALTIVEC_BUILTIN_VEC_MADD, - ALTIVEC_BUILTIN_VEC_MADDS, - ALTIVEC_BUILTIN_VEC_MAX, - ALTIVEC_BUILTIN_VEC_MERGEH, - ALTIVEC_BUILTIN_VEC_MERGEL, - ALTIVEC_BUILTIN_VEC_MIN, - ALTIVEC_BUILTIN_VEC_MLADD, - ALTIVEC_BUILTIN_VEC_MPERM, - ALTIVEC_BUILTIN_VEC_MRADDS, - ALTIVEC_BUILTIN_VEC_MRGHB, - ALTIVEC_BUILTIN_VEC_MRGHH, - ALTIVEC_BUILTIN_VEC_MRGHW, - ALTIVEC_BUILTIN_VEC_MRGLB, - ALTIVEC_BUILTIN_VEC_MRGLH, - ALTIVEC_BUILTIN_VEC_MRGLW, - ALTIVEC_BUILTIN_VEC_MSUM, - ALTIVEC_BUILTIN_VEC_MSUMS, - ALTIVEC_BUILTIN_VEC_MTVSCR, - ALTIVEC_BUILTIN_VEC_MULE, - ALTIVEC_BUILTIN_VEC_MULO, - ALTIVEC_BUILTIN_VEC_NEARBYINT, - ALTIVEC_BUILTIN_VEC_NMSUB, - ALTIVEC_BUILTIN_VEC_NOR, - ALTIVEC_BUILTIN_VEC_OR, - ALTIVEC_BUILTIN_VEC_PACK, - ALTIVEC_BUILTIN_VEC_PACKPX, - ALTIVEC_BUILTIN_VEC_PACKS, - ALTIVEC_BUILTIN_VEC_PACKSU, - ALTIVEC_BUILTIN_VEC_PERM, - ALTIVEC_BUILTIN_VEC_RE, - ALTIVEC_BUILTIN_VEC_RL, - ALTIVEC_BUILTIN_VEC_RINT, - ALTIVEC_BUILTIN_VEC_ROUND, - ALTIVEC_BUILTIN_VEC_RSQRTE, - ALTIVEC_BUILTIN_VEC_SEL, - ALTIVEC_BUILTIN_VEC_SL, - ALTIVEC_BUILTIN_VEC_SLD, - ALTIVEC_BUILTIN_VEC_SLL, - ALTIVEC_BUILTIN_VEC_SLO, - ALTIVEC_BUILTIN_VEC_SPLAT, - ALTIVEC_BUILTIN_VEC_SPLAT_S16, - ALTIVEC_BUILTIN_VEC_SPLAT_S32, - ALTIVEC_BUILTIN_VEC_SPLAT_S8, - ALTIVEC_BUILTIN_VEC_SPLAT_U16, - ALTIVEC_BUILTIN_VEC_SPLAT_U32, - ALTIVEC_BUILTIN_VEC_SPLAT_U8, - ALTIVEC_BUILTIN_VEC_SPLTB, - ALTIVEC_BUILTIN_VEC_SPLTH, - ALTIVEC_BUILTIN_VEC_SPLTW, - ALTIVEC_BUILTIN_VEC_SQRT, - ALTIVEC_BUILTIN_VEC_SR, - ALTIVEC_BUILTIN_VEC_SRA, - ALTIVEC_BUILTIN_VEC_SRL, - ALTIVEC_BUILTIN_VEC_SRO, - ALTIVEC_BUILTIN_VEC_ST, - ALTIVEC_BUILTIN_VEC_STE, - ALTIVEC_BUILTIN_VEC_STL, - ALTIVEC_BUILTIN_VEC_STVEBX, - ALTIVEC_BUILTIN_VEC_STVEHX, - ALTIVEC_BUILTIN_VEC_STVEWX, - ALTIVEC_BUILTIN_VEC_STVLX, - ALTIVEC_BUILTIN_VEC_STVLXL, - ALTIVEC_BUILTIN_VEC_STVRX, - ALTIVEC_BUILTIN_VEC_STVRXL, - ALTIVEC_BUILTIN_VEC_SUB, - ALTIVEC_BUILTIN_VEC_SUBC, - ALTIVEC_BUILTIN_VEC_SUBS, - ALTIVEC_BUILTIN_VEC_SUM2S, - ALTIVEC_BUILTIN_VEC_SUM4S, - ALTIVEC_BUILTIN_VEC_SUMS, - ALTIVEC_BUILTIN_VEC_TRUNC, - ALTIVEC_BUILTIN_VEC_UNPACKH, - ALTIVEC_BUILTIN_VEC_UNPACKL, - ALTIVEC_BUILTIN_VEC_VADDFP, - ALTIVEC_BUILTIN_VEC_VADDSBS, - ALTIVEC_BUILTIN_VEC_VADDSHS, - ALTIVEC_BUILTIN_VEC_VADDSWS, - ALTIVEC_BUILTIN_VEC_VADDUBM, - ALTIVEC_BUILTIN_VEC_VADDUBS, - ALTIVEC_BUILTIN_VEC_VADDUHM, - ALTIVEC_BUILTIN_VEC_VADDUHS, - ALTIVEC_BUILTIN_VEC_VADDUWM, - ALTIVEC_BUILTIN_VEC_VADDUWS, - ALTIVEC_BUILTIN_VEC_VAVGSB, - ALTIVEC_BUILTIN_VEC_VAVGSH, - ALTIVEC_BUILTIN_VEC_VAVGSW, - ALTIVEC_BUILTIN_VEC_VAVGUB, - ALTIVEC_BUILTIN_VEC_VAVGUH, - ALTIVEC_BUILTIN_VEC_VAVGUW, - ALTIVEC_BUILTIN_VEC_VCFSX, - ALTIVEC_BUILTIN_VEC_VCFUX, - ALTIVEC_BUILTIN_VEC_VCMPEQFP, - ALTIVEC_BUILTIN_VEC_VCMPEQUB, - ALTIVEC_BUILTIN_VEC_VCMPEQUH, - ALTIVEC_BUILTIN_VEC_VCMPEQUW, - ALTIVEC_BUILTIN_VEC_VCMPGTFP, - ALTIVEC_BUILTIN_VEC_VCMPGTSB, - ALTIVEC_BUILTIN_VEC_VCMPGTSH, - ALTIVEC_BUILTIN_VEC_VCMPGTSW, - ALTIVEC_BUILTIN_VEC_VCMPGTUB, - ALTIVEC_BUILTIN_VEC_VCMPGTUH, - ALTIVEC_BUILTIN_VEC_VCMPGTUW, - ALTIVEC_BUILTIN_VEC_VMAXFP, - ALTIVEC_BUILTIN_VEC_VMAXSB, - ALTIVEC_BUILTIN_VEC_VMAXSH, - ALTIVEC_BUILTIN_VEC_VMAXSW, - ALTIVEC_BUILTIN_VEC_VMAXUB, - ALTIVEC_BUILTIN_VEC_VMAXUH, - ALTIVEC_BUILTIN_VEC_VMAXUW, - ALTIVEC_BUILTIN_VEC_VMINFP, - ALTIVEC_BUILTIN_VEC_VMINSB, - ALTIVEC_BUILTIN_VEC_VMINSH, - ALTIVEC_BUILTIN_VEC_VMINSW, - ALTIVEC_BUILTIN_VEC_VMINUB, - ALTIVEC_BUILTIN_VEC_VMINUH, - ALTIVEC_BUILTIN_VEC_VMINUW, - ALTIVEC_BUILTIN_VEC_VMRGHB, - ALTIVEC_BUILTIN_VEC_VMRGHH, - ALTIVEC_BUILTIN_VEC_VMRGHW, - ALTIVEC_BUILTIN_VEC_VMRGLB, - ALTIVEC_BUILTIN_VEC_VMRGLH, - ALTIVEC_BUILTIN_VEC_VMRGLW, - ALTIVEC_BUILTIN_VEC_VMSUMMBM, - ALTIVEC_BUILTIN_VEC_VMSUMSHM, - ALTIVEC_BUILTIN_VEC_VMSUMSHS, - ALTIVEC_BUILTIN_VEC_VMSUMUBM, - ALTIVEC_BUILTIN_VEC_VMSUMUHM, - ALTIVEC_BUILTIN_VEC_VMSUMUHS, - ALTIVEC_BUILTIN_VEC_VMULESB, - ALTIVEC_BUILTIN_VEC_VMULESH, - ALTIVEC_BUILTIN_VEC_VMULEUB, - ALTIVEC_BUILTIN_VEC_VMULEUH, - ALTIVEC_BUILTIN_VEC_VMULOSB, - ALTIVEC_BUILTIN_VEC_VMULOSH, - ALTIVEC_BUILTIN_VEC_VMULOUB, - ALTIVEC_BUILTIN_VEC_VMULOUH, - ALTIVEC_BUILTIN_VEC_VPKSHSS, - ALTIVEC_BUILTIN_VEC_VPKSHUS, - ALTIVEC_BUILTIN_VEC_VPKSWSS, - ALTIVEC_BUILTIN_VEC_VPKSWUS, - ALTIVEC_BUILTIN_VEC_VPKUHUM, - ALTIVEC_BUILTIN_VEC_VPKUHUS, - ALTIVEC_BUILTIN_VEC_VPKUWUM, - ALTIVEC_BUILTIN_VEC_VPKUWUS, - ALTIVEC_BUILTIN_VEC_VRLB, - ALTIVEC_BUILTIN_VEC_VRLH, - ALTIVEC_BUILTIN_VEC_VRLW, - ALTIVEC_BUILTIN_VEC_VSLB, - ALTIVEC_BUILTIN_VEC_VSLH, - ALTIVEC_BUILTIN_VEC_VSLW, - ALTIVEC_BUILTIN_VEC_VSPLTB, - ALTIVEC_BUILTIN_VEC_VSPLTH, - ALTIVEC_BUILTIN_VEC_VSPLTW, - ALTIVEC_BUILTIN_VEC_VSRAB, - ALTIVEC_BUILTIN_VEC_VSRAH, - ALTIVEC_BUILTIN_VEC_VSRAW, - ALTIVEC_BUILTIN_VEC_VSRB, - ALTIVEC_BUILTIN_VEC_VSRH, - ALTIVEC_BUILTIN_VEC_VSRW, - ALTIVEC_BUILTIN_VEC_VSUBFP, - ALTIVEC_BUILTIN_VEC_VSUBSBS, - ALTIVEC_BUILTIN_VEC_VSUBSHS, - ALTIVEC_BUILTIN_VEC_VSUBSWS, - ALTIVEC_BUILTIN_VEC_VSUBUBM, - ALTIVEC_BUILTIN_VEC_VSUBUBS, - ALTIVEC_BUILTIN_VEC_VSUBUHM, - ALTIVEC_BUILTIN_VEC_VSUBUHS, - ALTIVEC_BUILTIN_VEC_VSUBUWM, - ALTIVEC_BUILTIN_VEC_VSUBUWS, - ALTIVEC_BUILTIN_VEC_VSUM4SBS, - ALTIVEC_BUILTIN_VEC_VSUM4SHS, - ALTIVEC_BUILTIN_VEC_VSUM4UBS, - ALTIVEC_BUILTIN_VEC_VUPKHPX, - ALTIVEC_BUILTIN_VEC_VUPKHSB, - ALTIVEC_BUILTIN_VEC_VUPKHSH, - ALTIVEC_BUILTIN_VEC_VUPKLPX, - ALTIVEC_BUILTIN_VEC_VUPKLSB, - ALTIVEC_BUILTIN_VEC_VUPKLSH, - ALTIVEC_BUILTIN_VEC_XOR, - ALTIVEC_BUILTIN_VEC_STEP, - ALTIVEC_BUILTIN_VEC_PROMOTE, - ALTIVEC_BUILTIN_VEC_INSERT, - ALTIVEC_BUILTIN_VEC_SPLATS, - ALTIVEC_BUILTIN_OVERLOADED_LAST = ALTIVEC_BUILTIN_VEC_SPLATS, - - /* SPE builtins. */ - SPE_BUILTIN_EVADDW, - SPE_BUILTIN_EVAND, - SPE_BUILTIN_EVANDC, - SPE_BUILTIN_EVDIVWS, - SPE_BUILTIN_EVDIVWU, - SPE_BUILTIN_EVEQV, - SPE_BUILTIN_EVFSADD, - SPE_BUILTIN_EVFSDIV, - SPE_BUILTIN_EVFSMUL, - SPE_BUILTIN_EVFSSUB, - SPE_BUILTIN_EVLDDX, - SPE_BUILTIN_EVLDHX, - SPE_BUILTIN_EVLDWX, - SPE_BUILTIN_EVLHHESPLATX, - SPE_BUILTIN_EVLHHOSSPLATX, - SPE_BUILTIN_EVLHHOUSPLATX, - SPE_BUILTIN_EVLWHEX, - SPE_BUILTIN_EVLWHOSX, - SPE_BUILTIN_EVLWHOUX, - SPE_BUILTIN_EVLWHSPLATX, - SPE_BUILTIN_EVLWWSPLATX, - SPE_BUILTIN_EVMERGEHI, - SPE_BUILTIN_EVMERGEHILO, - SPE_BUILTIN_EVMERGELO, - SPE_BUILTIN_EVMERGELOHI, - SPE_BUILTIN_EVMHEGSMFAA, - SPE_BUILTIN_EVMHEGSMFAN, - SPE_BUILTIN_EVMHEGSMIAA, - SPE_BUILTIN_EVMHEGSMIAN, - SPE_BUILTIN_EVMHEGUMIAA, - SPE_BUILTIN_EVMHEGUMIAN, - SPE_BUILTIN_EVMHESMF, - SPE_BUILTIN_EVMHESMFA, - SPE_BUILTIN_EVMHESMFAAW, - SPE_BUILTIN_EVMHESMFANW, - SPE_BUILTIN_EVMHESMI, - SPE_BUILTIN_EVMHESMIA, - SPE_BUILTIN_EVMHESMIAAW, - SPE_BUILTIN_EVMHESMIANW, - SPE_BUILTIN_EVMHESSF, - SPE_BUILTIN_EVMHESSFA, - SPE_BUILTIN_EVMHESSFAAW, - SPE_BUILTIN_EVMHESSFANW, - SPE_BUILTIN_EVMHESSIAAW, - SPE_BUILTIN_EVMHESSIANW, - SPE_BUILTIN_EVMHEUMI, - SPE_BUILTIN_EVMHEUMIA, - SPE_BUILTIN_EVMHEUMIAAW, - SPE_BUILTIN_EVMHEUMIANW, - SPE_BUILTIN_EVMHEUSIAAW, - SPE_BUILTIN_EVMHEUSIANW, - SPE_BUILTIN_EVMHOGSMFAA, - SPE_BUILTIN_EVMHOGSMFAN, - SPE_BUILTIN_EVMHOGSMIAA, - SPE_BUILTIN_EVMHOGSMIAN, - SPE_BUILTIN_EVMHOGUMIAA, - SPE_BUILTIN_EVMHOGUMIAN, - SPE_BUILTIN_EVMHOSMF, - SPE_BUILTIN_EVMHOSMFA, - SPE_BUILTIN_EVMHOSMFAAW, - SPE_BUILTIN_EVMHOSMFANW, - SPE_BUILTIN_EVMHOSMI, - SPE_BUILTIN_EVMHOSMIA, - SPE_BUILTIN_EVMHOSMIAAW, - SPE_BUILTIN_EVMHOSMIANW, - SPE_BUILTIN_EVMHOSSF, - SPE_BUILTIN_EVMHOSSFA, - SPE_BUILTIN_EVMHOSSFAAW, - SPE_BUILTIN_EVMHOSSFANW, - SPE_BUILTIN_EVMHOSSIAAW, - SPE_BUILTIN_EVMHOSSIANW, - SPE_BUILTIN_EVMHOUMI, - SPE_BUILTIN_EVMHOUMIA, - SPE_BUILTIN_EVMHOUMIAAW, - SPE_BUILTIN_EVMHOUMIANW, - SPE_BUILTIN_EVMHOUSIAAW, - SPE_BUILTIN_EVMHOUSIANW, - SPE_BUILTIN_EVMWHSMF, - SPE_BUILTIN_EVMWHSMFA, - SPE_BUILTIN_EVMWHSMI, - SPE_BUILTIN_EVMWHSMIA, - SPE_BUILTIN_EVMWHSSF, - SPE_BUILTIN_EVMWHSSFA, - SPE_BUILTIN_EVMWHUMI, - SPE_BUILTIN_EVMWHUMIA, - SPE_BUILTIN_EVMWLSMIAAW, - SPE_BUILTIN_EVMWLSMIANW, - SPE_BUILTIN_EVMWLSSIAAW, - SPE_BUILTIN_EVMWLSSIANW, - SPE_BUILTIN_EVMWLUMI, - SPE_BUILTIN_EVMWLUMIA, - SPE_BUILTIN_EVMWLUMIAAW, - SPE_BUILTIN_EVMWLUMIANW, - SPE_BUILTIN_EVMWLUSIAAW, - SPE_BUILTIN_EVMWLUSIANW, - SPE_BUILTIN_EVMWSMF, - SPE_BUILTIN_EVMWSMFA, - SPE_BUILTIN_EVMWSMFAA, - SPE_BUILTIN_EVMWSMFAN, - SPE_BUILTIN_EVMWSMI, - SPE_BUILTIN_EVMWSMIA, - SPE_BUILTIN_EVMWSMIAA, - SPE_BUILTIN_EVMWSMIAN, - SPE_BUILTIN_EVMWHSSFAA, - SPE_BUILTIN_EVMWSSF, - SPE_BUILTIN_EVMWSSFA, - SPE_BUILTIN_EVMWSSFAA, - SPE_BUILTIN_EVMWSSFAN, - SPE_BUILTIN_EVMWUMI, - SPE_BUILTIN_EVMWUMIA, - SPE_BUILTIN_EVMWUMIAA, - SPE_BUILTIN_EVMWUMIAN, - SPE_BUILTIN_EVNAND, - SPE_BUILTIN_EVNOR, - SPE_BUILTIN_EVOR, - SPE_BUILTIN_EVORC, - SPE_BUILTIN_EVRLW, - SPE_BUILTIN_EVSLW, - SPE_BUILTIN_EVSRWS, - SPE_BUILTIN_EVSRWU, - SPE_BUILTIN_EVSTDDX, - SPE_BUILTIN_EVSTDHX, - SPE_BUILTIN_EVSTDWX, - SPE_BUILTIN_EVSTWHEX, - SPE_BUILTIN_EVSTWHOX, - SPE_BUILTIN_EVSTWWEX, - SPE_BUILTIN_EVSTWWOX, - SPE_BUILTIN_EVSUBFW, - SPE_BUILTIN_EVXOR, - SPE_BUILTIN_EVABS, - SPE_BUILTIN_EVADDSMIAAW, - SPE_BUILTIN_EVADDSSIAAW, - SPE_BUILTIN_EVADDUMIAAW, - SPE_BUILTIN_EVADDUSIAAW, - SPE_BUILTIN_EVCNTLSW, - SPE_BUILTIN_EVCNTLZW, - SPE_BUILTIN_EVEXTSB, - SPE_BUILTIN_EVEXTSH, - SPE_BUILTIN_EVFSABS, - SPE_BUILTIN_EVFSCFSF, - SPE_BUILTIN_EVFSCFSI, - SPE_BUILTIN_EVFSCFUF, - SPE_BUILTIN_EVFSCFUI, - SPE_BUILTIN_EVFSCTSF, - SPE_BUILTIN_EVFSCTSI, - SPE_BUILTIN_EVFSCTSIZ, - SPE_BUILTIN_EVFSCTUF, - SPE_BUILTIN_EVFSCTUI, - SPE_BUILTIN_EVFSCTUIZ, - SPE_BUILTIN_EVFSNABS, - SPE_BUILTIN_EVFSNEG, - SPE_BUILTIN_EVMRA, - SPE_BUILTIN_EVNEG, - SPE_BUILTIN_EVRNDW, - SPE_BUILTIN_EVSUBFSMIAAW, - SPE_BUILTIN_EVSUBFSSIAAW, - SPE_BUILTIN_EVSUBFUMIAAW, - SPE_BUILTIN_EVSUBFUSIAAW, - SPE_BUILTIN_EVADDIW, - SPE_BUILTIN_EVLDD, - SPE_BUILTIN_EVLDH, - SPE_BUILTIN_EVLDW, - SPE_BUILTIN_EVLHHESPLAT, - SPE_BUILTIN_EVLHHOSSPLAT, - SPE_BUILTIN_EVLHHOUSPLAT, - SPE_BUILTIN_EVLWHE, - SPE_BUILTIN_EVLWHOS, - SPE_BUILTIN_EVLWHOU, - SPE_BUILTIN_EVLWHSPLAT, - SPE_BUILTIN_EVLWWSPLAT, - SPE_BUILTIN_EVRLWI, - SPE_BUILTIN_EVSLWI, - SPE_BUILTIN_EVSRWIS, - SPE_BUILTIN_EVSRWIU, - SPE_BUILTIN_EVSTDD, - SPE_BUILTIN_EVSTDH, - SPE_BUILTIN_EVSTDW, - SPE_BUILTIN_EVSTWHE, - SPE_BUILTIN_EVSTWHO, - SPE_BUILTIN_EVSTWWE, - SPE_BUILTIN_EVSTWWO, - SPE_BUILTIN_EVSUBIFW, - - /* Compares. */ - SPE_BUILTIN_EVCMPEQ, - SPE_BUILTIN_EVCMPGTS, - SPE_BUILTIN_EVCMPGTU, - SPE_BUILTIN_EVCMPLTS, - SPE_BUILTIN_EVCMPLTU, - SPE_BUILTIN_EVFSCMPEQ, - SPE_BUILTIN_EVFSCMPGT, - SPE_BUILTIN_EVFSCMPLT, - SPE_BUILTIN_EVFSTSTEQ, - SPE_BUILTIN_EVFSTSTGT, - SPE_BUILTIN_EVFSTSTLT, - - /* EVSEL compares. */ - SPE_BUILTIN_EVSEL_CMPEQ, - SPE_BUILTIN_EVSEL_CMPGTS, - SPE_BUILTIN_EVSEL_CMPGTU, - SPE_BUILTIN_EVSEL_CMPLTS, - SPE_BUILTIN_EVSEL_CMPLTU, - SPE_BUILTIN_EVSEL_FSCMPEQ, - SPE_BUILTIN_EVSEL_FSCMPGT, - SPE_BUILTIN_EVSEL_FSCMPLT, - SPE_BUILTIN_EVSEL_FSTSTEQ, - SPE_BUILTIN_EVSEL_FSTSTGT, - SPE_BUILTIN_EVSEL_FSTSTLT, - - SPE_BUILTIN_EVSPLATFI, - SPE_BUILTIN_EVSPLATI, - SPE_BUILTIN_EVMWHSSMAA, - SPE_BUILTIN_EVMWHSMFAA, - SPE_BUILTIN_EVMWHSMIAA, - SPE_BUILTIN_EVMWHUSIAA, - SPE_BUILTIN_EVMWHUMIAA, - SPE_BUILTIN_EVMWHSSFAN, - SPE_BUILTIN_EVMWHSSIAN, - SPE_BUILTIN_EVMWHSMFAN, - SPE_BUILTIN_EVMWHSMIAN, - SPE_BUILTIN_EVMWHUSIAN, - SPE_BUILTIN_EVMWHUMIAN, - SPE_BUILTIN_EVMWHGSSFAA, - SPE_BUILTIN_EVMWHGSMFAA, - SPE_BUILTIN_EVMWHGSMIAA, - SPE_BUILTIN_EVMWHGUMIAA, - SPE_BUILTIN_EVMWHGSSFAN, - SPE_BUILTIN_EVMWHGSMFAN, - SPE_BUILTIN_EVMWHGSMIAN, - SPE_BUILTIN_EVMWHGUMIAN, - SPE_BUILTIN_MTSPEFSCR, - SPE_BUILTIN_MFSPEFSCR, - SPE_BUILTIN_BRINC, - - /* PAIRED builtins. */ - PAIRED_BUILTIN_DIVV2SF3, - PAIRED_BUILTIN_ABSV2SF2, - PAIRED_BUILTIN_NEGV2SF2, - PAIRED_BUILTIN_SQRTV2SF2, - PAIRED_BUILTIN_ADDV2SF3, - PAIRED_BUILTIN_SUBV2SF3, - PAIRED_BUILTIN_RESV2SF2, - PAIRED_BUILTIN_MULV2SF3, - PAIRED_BUILTIN_MSUB, - PAIRED_BUILTIN_MADD, - PAIRED_BUILTIN_NMSUB, - PAIRED_BUILTIN_NMADD, - PAIRED_BUILTIN_NABSV2SF2, - PAIRED_BUILTIN_SUM0, - PAIRED_BUILTIN_SUM1, - PAIRED_BUILTIN_MULS0, - PAIRED_BUILTIN_MULS1, - PAIRED_BUILTIN_MERGE00, - PAIRED_BUILTIN_MERGE01, - PAIRED_BUILTIN_MERGE10, - PAIRED_BUILTIN_MERGE11, - PAIRED_BUILTIN_MADDS0, - PAIRED_BUILTIN_MADDS1, - PAIRED_BUILTIN_STX, - PAIRED_BUILTIN_LX, - PAIRED_BUILTIN_SELV2SF4, - PAIRED_BUILTIN_CMPU0, - PAIRED_BUILTIN_CMPU1, - - RS6000_BUILTIN_RECIP, - RS6000_BUILTIN_RECIPF, - RS6000_BUILTIN_RSQRTF, - RS6000_BUILTIN_BSWAP_HI, - - /* VSX builtins. */ - VSX_BUILTIN_LXSDX, - VSX_BUILTIN_LXVD2X, - VSX_BUILTIN_LXVDSX, - VSX_BUILTIN_LXVW4X, - VSX_BUILTIN_STXSDX, - VSX_BUILTIN_STXVD2X, - VSX_BUILTIN_STXVW4X, - VSX_BUILTIN_XSABSDP, - VSX_BUILTIN_XSADDDP, - VSX_BUILTIN_XSCMPODP, - VSX_BUILTIN_XSCMPUDP, - VSX_BUILTIN_XSCPSGNDP, - VSX_BUILTIN_XSCVDPSP, - VSX_BUILTIN_XSCVDPSXDS, - VSX_BUILTIN_XSCVDPSXWS, - VSX_BUILTIN_XSCVDPUXDS, - VSX_BUILTIN_XSCVDPUXWS, - VSX_BUILTIN_XSCVSPDP, - VSX_BUILTIN_XSCVSXDDP, - VSX_BUILTIN_XSCVUXDDP, - VSX_BUILTIN_XSDIVDP, - VSX_BUILTIN_XSMADDADP, - VSX_BUILTIN_XSMADDMDP, - VSX_BUILTIN_XSMAXDP, - VSX_BUILTIN_XSMINDP, - VSX_BUILTIN_XSMOVDP, - VSX_BUILTIN_XSMSUBADP, - VSX_BUILTIN_XSMSUBMDP, - VSX_BUILTIN_XSMULDP, - VSX_BUILTIN_XSNABSDP, - VSX_BUILTIN_XSNEGDP, - VSX_BUILTIN_XSNMADDADP, - VSX_BUILTIN_XSNMADDMDP, - VSX_BUILTIN_XSNMSUBADP, - VSX_BUILTIN_XSNMSUBMDP, - VSX_BUILTIN_XSRDPI, - VSX_BUILTIN_XSRDPIC, - VSX_BUILTIN_XSRDPIM, - VSX_BUILTIN_XSRDPIP, - VSX_BUILTIN_XSRDPIZ, - VSX_BUILTIN_XSREDP, - VSX_BUILTIN_XSRSQRTEDP, - VSX_BUILTIN_XSSQRTDP, - VSX_BUILTIN_XSSUBDP, - VSX_BUILTIN_CPSGNDP, - VSX_BUILTIN_CPSGNSP, - VSX_BUILTIN_XSTDIVDP_FE, - VSX_BUILTIN_XSTDIVDP_FG, - VSX_BUILTIN_XSTSQRTDP_FE, - VSX_BUILTIN_XSTSQRTDP_FG, - VSX_BUILTIN_XVABSDP, - VSX_BUILTIN_XVABSSP, - VSX_BUILTIN_XVADDDP, - VSX_BUILTIN_XVADDSP, - VSX_BUILTIN_XVCMPEQDP, - VSX_BUILTIN_XVCMPEQSP, - VSX_BUILTIN_XVCMPGEDP, - VSX_BUILTIN_XVCMPGESP, - VSX_BUILTIN_XVCMPGTDP, - VSX_BUILTIN_XVCMPGTSP, - VSX_BUILTIN_XVCMPEQDP_P, - VSX_BUILTIN_XVCMPEQSP_P, - VSX_BUILTIN_XVCMPGEDP_P, - VSX_BUILTIN_XVCMPGESP_P, - VSX_BUILTIN_XVCMPGTDP_P, - VSX_BUILTIN_XVCMPGTSP_P, - VSX_BUILTIN_XVCPSGNDP, - VSX_BUILTIN_XVCPSGNSP, - VSX_BUILTIN_XVCVDPSP, - VSX_BUILTIN_XVCVDPSXDS, - VSX_BUILTIN_XVCVDPSXWS, - VSX_BUILTIN_XVCVDPUXDS, - VSX_BUILTIN_XVCVDPUXDS_UNS, - VSX_BUILTIN_XVCVDPUXWS, - VSX_BUILTIN_XVCVSPDP, - VSX_BUILTIN_XVCVSPSXDS, - VSX_BUILTIN_XVCVSPSXWS, - VSX_BUILTIN_XVCVSPUXDS, - VSX_BUILTIN_XVCVSPUXWS, - VSX_BUILTIN_XVCVSXDDP, - VSX_BUILTIN_XVCVSXDSP, - VSX_BUILTIN_XVCVSXWDP, - VSX_BUILTIN_XVCVSXWSP, - VSX_BUILTIN_XVCVUXDDP, - VSX_BUILTIN_XVCVUXDDP_UNS, - VSX_BUILTIN_XVCVUXDSP, - VSX_BUILTIN_XVCVUXWDP, - VSX_BUILTIN_XVCVUXWSP, - VSX_BUILTIN_XVDIVDP, - VSX_BUILTIN_XVDIVSP, - VSX_BUILTIN_XVMADDDP, - VSX_BUILTIN_XVMADDSP, - VSX_BUILTIN_XVMAXDP, - VSX_BUILTIN_XVMAXSP, - VSX_BUILTIN_XVMINDP, - VSX_BUILTIN_XVMINSP, - VSX_BUILTIN_XVMSUBDP, - VSX_BUILTIN_XVMSUBSP, - VSX_BUILTIN_XVMULDP, - VSX_BUILTIN_XVMULSP, - VSX_BUILTIN_XVNABSDP, - VSX_BUILTIN_XVNABSSP, - VSX_BUILTIN_XVNEGDP, - VSX_BUILTIN_XVNEGSP, - VSX_BUILTIN_XVNMADDDP, - VSX_BUILTIN_XVNMADDSP, - VSX_BUILTIN_XVNMSUBDP, - VSX_BUILTIN_XVNMSUBSP, - VSX_BUILTIN_XVRDPI, - VSX_BUILTIN_XVRDPIC, - VSX_BUILTIN_XVRDPIM, - VSX_BUILTIN_XVRDPIP, - VSX_BUILTIN_XVRDPIZ, - VSX_BUILTIN_XVREDP, - VSX_BUILTIN_XVRESP, - VSX_BUILTIN_XVRSPI, - VSX_BUILTIN_XVRSPIC, - VSX_BUILTIN_XVRSPIM, - VSX_BUILTIN_XVRSPIP, - VSX_BUILTIN_XVRSPIZ, - VSX_BUILTIN_XVRSQRTEDP, - VSX_BUILTIN_XVRSQRTESP, - VSX_BUILTIN_XVSQRTDP, - VSX_BUILTIN_XVSQRTSP, - VSX_BUILTIN_XVSUBDP, - VSX_BUILTIN_XVSUBSP, - VSX_BUILTIN_XVTDIVDP_FE, - VSX_BUILTIN_XVTDIVDP_FG, - VSX_BUILTIN_XVTDIVSP_FE, - VSX_BUILTIN_XVTDIVSP_FG, - VSX_BUILTIN_XVTSQRTDP_FE, - VSX_BUILTIN_XVTSQRTDP_FG, - VSX_BUILTIN_XVTSQRTSP_FE, - VSX_BUILTIN_XVTSQRTSP_FG, - VSX_BUILTIN_XXSEL_2DI, - VSX_BUILTIN_XXSEL_2DF, - VSX_BUILTIN_XXSEL_4SI, - VSX_BUILTIN_XXSEL_4SF, - VSX_BUILTIN_XXSEL_8HI, - VSX_BUILTIN_XXSEL_16QI, - VSX_BUILTIN_XXSEL_2DI_UNS, - VSX_BUILTIN_XXSEL_4SI_UNS, - VSX_BUILTIN_XXSEL_8HI_UNS, - VSX_BUILTIN_XXSEL_16QI_UNS, - VSX_BUILTIN_VPERM_2DI, - VSX_BUILTIN_VPERM_2DF, - VSX_BUILTIN_VPERM_4SI, - VSX_BUILTIN_VPERM_4SF, - VSX_BUILTIN_VPERM_8HI, - VSX_BUILTIN_VPERM_16QI, - VSX_BUILTIN_VPERM_2DI_UNS, - VSX_BUILTIN_VPERM_4SI_UNS, - VSX_BUILTIN_VPERM_8HI_UNS, - VSX_BUILTIN_VPERM_16QI_UNS, - VSX_BUILTIN_XXPERMDI_2DF, - VSX_BUILTIN_XXPERMDI_2DI, - VSX_BUILTIN_XXPERMDI_4SF, - VSX_BUILTIN_XXPERMDI_4SI, - VSX_BUILTIN_XXPERMDI_8HI, - VSX_BUILTIN_XXPERMDI_16QI, - VSX_BUILTIN_CONCAT_2DF, - VSX_BUILTIN_CONCAT_2DI, - VSX_BUILTIN_SET_2DF, - VSX_BUILTIN_SET_2DI, - VSX_BUILTIN_SPLAT_2DF, - VSX_BUILTIN_SPLAT_2DI, - VSX_BUILTIN_XXMRGHW_4SF, - VSX_BUILTIN_XXMRGHW_4SI, - VSX_BUILTIN_XXMRGLW_4SF, - VSX_BUILTIN_XXMRGLW_4SI, - VSX_BUILTIN_XXSLDWI_16QI, - VSX_BUILTIN_XXSLDWI_8HI, - VSX_BUILTIN_XXSLDWI_4SI, - VSX_BUILTIN_XXSLDWI_4SF, - VSX_BUILTIN_XXSLDWI_2DI, - VSX_BUILTIN_XXSLDWI_2DF, - VSX_BUILTIN_VEC_INIT_V2DF, - VSX_BUILTIN_VEC_INIT_V2DI, - VSX_BUILTIN_VEC_SET_V2DF, - VSX_BUILTIN_VEC_SET_V2DI, - VSX_BUILTIN_VEC_EXT_V2DF, - VSX_BUILTIN_VEC_EXT_V2DI, - - /* VSX overloaded builtins, add the overloaded functions not present in - Altivec. */ - VSX_BUILTIN_VEC_MUL, - VSX_BUILTIN_OVERLOADED_FIRST = VSX_BUILTIN_VEC_MUL, - VSX_BUILTIN_VEC_MSUB, - VSX_BUILTIN_VEC_NMADD, - VSX_BUITLIN_VEC_NMSUB, - VSX_BUILTIN_VEC_DIV, - VSX_BUILTIN_VEC_XXMRGHW, - VSX_BUILTIN_VEC_XXMRGLW, - VSX_BUILTIN_VEC_XXPERMDI, - VSX_BUILTIN_VEC_XXSLDWI, - VSX_BUILTIN_VEC_XXSPLTD, - VSX_BUILTIN_VEC_XXSPLTW, - VSX_BUILTIN_OVERLOADED_LAST = VSX_BUILTIN_VEC_XXSPLTW, - - /* Combined VSX/Altivec builtins. */ - VECTOR_BUILTIN_FLOAT_V4SI_V4SF, - VECTOR_BUILTIN_UNSFLOAT_V4SI_V4SF, - VECTOR_BUILTIN_FIX_V4SF_V4SI, - VECTOR_BUILTIN_FIXUNS_V4SF_V4SI, - - /* Power7 builtins, that aren't VSX instructions. */ - POWER7_BUILTIN_BPERMD, +#include "rs6000-builtin.def" RS6000_BUILTIN_COUNT }; +#undef RS6000_BUILTIN +#undef RS6000_BUILTIN_EQUATE + enum rs6000_builtin_type_index { RS6000_BTI_NOT_OPAQUE, diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index ba51f1cebc7..7ff1b3c1a47 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -117,7 +117,7 @@ ;; Define an insn type attribute. This is used in function unit delay ;; computations. -(define_attr "type" "integer,two,three,load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,store,store_ux,store_u,fpload,fpload_ux,fpload_u,fpstore,fpstore_ux,fpstore_u,vecload,vecstore,imul,imul2,imul3,lmul,idiv,ldiv,insert_word,branch,cmp,fast_compare,compare,var_delayed_compare,delayed_compare,imul_compare,lmul_compare,fpcompare,cr_logical,delayed_cr,mfcr,mfcrf,mtcr,mfjmpr,mtjmpr,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg,brinc,vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,vecfloat,vecfdiv,isync,sync,load_l,store_c,shift,trap,insert_dword,var_shift_rotate,cntlz,exts,mffgpr,mftgpr" +(define_attr "type" "integer,two,three,load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,store,store_ux,store_u,fpload,fpload_ux,fpload_u,fpstore,fpstore_ux,fpstore_u,vecload,vecstore,imul,imul2,imul3,lmul,idiv,ldiv,insert_word,branch,cmp,fast_compare,compare,var_delayed_compare,delayed_compare,imul_compare,lmul_compare,fpcompare,cr_logical,delayed_cr,mfcr,mfcrf,mtcr,mfjmpr,mtjmpr,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg,brinc,vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,vecfloat,vecfdiv,isync,sync,load_l,store_c,shift,trap,insert_dword,var_shift_rotate,cntlz,exts,mffgpr,mftgpr,isel" (const_string "integer")) ;; Define floating point instruction sub-types for use with Xfpu.md @@ -139,7 +139,7 @@ ;; Processor type -- this attribute must exactly match the processor_type ;; enumeration in rs6000.h. -(define_attr "cpu" "rios1,rios2,rs64a,mpccore,ppc403,ppc405,ppc440,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,ppc750,ppc7400,ppc7450,ppc8540,ppce300c2,ppce300c3,ppce500mc,power4,power5,power6,power7,cell" +(define_attr "cpu" "rios1,rios2,rs64a,mpccore,ppc403,ppc405,ppc440,ppc476,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,ppc750,ppc7400,ppc7450,ppc8540,ppce300c2,ppce300c3,ppce500mc,power4,power5,power6,power7,cell,ppca2" (const (symbol_ref "rs6000_cpu_attr"))) @@ -158,6 +158,7 @@ (include "mpc.md") (include "40x.md") (include "440.md") +(include "476.md") (include "603.md") (include "6xx.md") (include "7xx.md") @@ -171,6 +172,7 @@ (include "power7.md") (include "cell.md") (include "xfpu.md") +(include "a2.md") (include "predicates.md") (include "constraints.md") @@ -974,7 +976,7 @@ [(set_attr "type" "compare") (set_attr "length" "4,8")]) -;; IBM 405, 440 and 464 half-word multiplication operations. +;; IBM 405, 440, 464 and 476 half-word multiplication operations. (define_insn "*macchwc" [(set (match_operand:CC 3 "cc_reg_operand" "=x") @@ -1438,7 +1440,7 @@ "mullhwu %0, %1, %2" [(set_attr "type" "imul3")]) -;; IBM 405, 440 and 464 string-search dlmzb instruction support. +;; IBM 405, 440, 464 and 476 string-search dlmzb instruction support. (define_insn "dlmzb" [(set (match_operand:CC 3 "cc_reg_operand" "=x") (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r") @@ -6040,7 +6042,8 @@ "TARGET_ISEL" "* { return output_isel (operands); }" - [(set_attr "length" "4")]) + [(set_attr "type" "isel") + (set_attr "length" "4")]) (define_insn "isel_unsigned_" [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") @@ -6053,7 +6056,8 @@ "TARGET_ISEL" "* { return output_isel (operands); }" - [(set_attr "length" "4")]) + [(set_attr "type" "isel") + (set_attr "length" "4")]) (define_expand "movsfcc" [(set (match_operand:SF 0 "gpc_reg_operand" "") diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt index 90af9dce47b..63f0f8c1582 100644 --- a/gcc/config/rs6000/rs6000.opt +++ b/gcc/config/rs6000/rs6000.opt @@ -155,8 +155,12 @@ mvectorize-builtins Target Undocumented Report Var(TARGET_VECTORIZE_BUILTINS) Init(-1) ; Explicitly control whether we vectorize the builtins or not. +mno-update +Target Report RejectNegative Mask(NO_UPDATE) +Do not generate load/store with update instructions + mupdate -Target Report Var(TARGET_UPDATE) Init(1) +Target Report RejectNegative InverseMask(NO_UPDATE, UPDATE) Generate load/store with update instructions mavoid-indexed-addresses diff --git a/gcc/config/rs6000/rs64.md b/gcc/config/rs6000/rs64.md index f7234408ade..e221b52a370 100644 --- a/gcc/config/rs6000/rs64.md +++ b/gcc/config/rs6000/rs64.md @@ -1,5 +1,5 @@ ;; Scheduling description for IBM RS64 processors. -;; Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc. +;; Copyright (C) 2003, 2004, 2007, 2009 Free Software Foundation, Inc. ;; ;; This file is part of GCC. @@ -47,7 +47,7 @@ (define_insn_reservation "rs64a-integer" 1 (and (eq_attr "type" "integer,insert_word,insert_dword,shift,trap,\ - var_shift_rotate,cntlz,exts") + var_shift_rotate,cntlz,exts,isel") (eq_attr "cpu" "rs64a")) "iu_rs64") diff --git a/gcc/config/rs6000/t-fprules b/gcc/config/rs6000/t-fprules index 272e00c1ada..42d8fd77b5b 100644 --- a/gcc/config/rs6000/t-fprules +++ b/gcc/config/rs6000/t-fprules @@ -21,6 +21,7 @@ MULTILIB_MATCHES_FLOAT = msoft-float=mcpu?401 \ msoft-float=mcpu?405 \ msoft-float=mcpu?440 \ msoft-float=mcpu?464 \ + msoft-float=mcpu?476 \ msoft-float=mcpu?ec603e \ msoft-float=mcpu?801 \ msoft-float=mcpu?821 \ diff --git a/gcc/config/rs6000/t-rs6000 b/gcc/config/rs6000/t-rs6000 index 66a367a7b62..773d710fa3f 100644 --- a/gcc/config/rs6000/t-rs6000 +++ b/gcc/config/rs6000/t-rs6000 @@ -19,6 +19,8 @@ # along with GCC; see the file COPYING3. If not see # . +TM_H += $(srcdir)/config/rs6000/rs6000-builtin.def + rs6000.o: $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(REGS_H) hard-reg-set.h \ real.h insn-config.h conditions.h insn-attr.h flags.h $(RECOG_H) \ @@ -56,6 +58,7 @@ MD_INCLUDES = $(srcdir)/config/rs6000/rios1.md \ $(srcdir)/config/rs6000/power7.md \ $(srcdir)/config/rs6000/cell.md \ $(srcdir)/config/rs6000/xfpu.md \ + $(srcdir)/config/rs6000/a2.md \ $(srcdir)/config/rs6000/predicates.md \ $(srcdir)/config/rs6000/constraints.md \ $(srcdir)/config/rs6000/darwin.md \ diff --git a/gcc/config/rs6000/vxworks.h b/gcc/config/rs6000/vxworks.h index cfd11eb6d79..c302ad2015d 100644 --- a/gcc/config/rs6000/vxworks.h +++ b/gcc/config/rs6000/vxworks.h @@ -1,5 +1,5 @@ /* Definitions of target machine for GNU compiler. Vxworks PowerPC version. - Copyright (C) 1996, 2000, 2002, 2003, 2004, 2005, 2007 + Copyright (C) 1996, 2000, 2002, 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc. Contributed by CodeSourcery, LLC. @@ -68,6 +68,8 @@ along with GCC; see the file COPYING3. If not see %{mcpu=403 : -DCPU=PPC403 ; \ mcpu=405 : -DCPU=PPC405 ; \ mcpu=440 : -DCPU=PPC440 ; \ + mcpu=464 : -DCPU=PPC464 ; \ + mcpu=476 : -DCPU=PPC476 ; \ mcpu=603 : -DCPU=PPC603 ; \ mcpu=604 : -DCPU=PPC604 ; \ mcpu=860 : -DCPU=PPC860 ; \ diff --git a/gcc/config/rx/constraints.md b/gcc/config/rx/constraints.md new file mode 100644 index 00000000000..52bf7df3621 --- /dev/null +++ b/gcc/config/rx/constraints.md @@ -0,0 +1,81 @@ +;; Constraint definitions for Renesas RX. +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. +;; +;; 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 3, 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 COPYING3. If not see +;; . + + +(define_constraint "Symbol" + "@internal Constraint on the type of rtx allowed in call insns" + (match_test "GET_CODE (op) == SYMBOL_REF") +) + + +(define_constraint "Int08" + "@internal A signed or unsigned 8-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 8), (1 << 8) - 1)") + ) +) + +(define_constraint "Sint08" + "@internal A signed 8-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 7), (1 << 7) - 1)") + ) +) + +(define_constraint "Sint16" + "@internal A signed 16-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 15), (1 << 15) - 1)") + ) +) + +(define_constraint "Sint24" + "@internal A signed 24-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, (-1 << 23), (1 << 23) - 1)") + ) +) + +;; This constraint is used by the SUBSI3 pattern because the +;; RX SUB instruction can only take a 4-bit unsigned integer +;; value. Also used by the MVTIPL instruction. +(define_constraint "Uint04" + "@internal An unsigned 4-bit immediate value" + (and (match_code "const_int") + (match_test "IN_RANGE (ival, 0, 15)") + ) +) + +;; This is used in arithmetic and logic instructions for +;; a source operand that lies in memory and which satisfies +;; rx_restricted_memory_address(). + +(define_memory_constraint "Q" + "A MEM which only uses REG or REG+INT addressing." + (and (match_code "mem") + (ior (match_code "reg" "0") + (and (match_code "plus" "0") + (and (match_code "reg,subreg" "00") + (match_code "const_int" "01") + ) + ) + ) + ) +) diff --git a/gcc/config/rx/predicates.md b/gcc/config/rx/predicates.md new file mode 100644 index 00000000000..d7a363ebb88 --- /dev/null +++ b/gcc/config/rx/predicates.md @@ -0,0 +1,288 @@ +;; Predicate definitions for Renesas RX. +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. +;; +;; 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 3, 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 COPYING3. If not see +;; . + + + +;; Check that the operand is suitable for a call insn. +;; Only registers and symbol refs are allowed. + +(define_predicate "rx_call_operand" + (match_code "symbol_ref,reg") +) + +;; For sibcall operations we can only use a symbolic address. + +(define_predicate "rx_symbolic_call_operand" + (match_code "symbol_ref") +) + +;; Check that the operand is suitable for a shift insn +;; Only small integers or a value in a register are permitted. + +(define_predicate "rx_shift_operand" + (match_code "const_int,reg") + { + if (CONST_INT_P (op)) + return IN_RANGE (INTVAL (op), 0, 31); + return true; + } +) + +;; Check that the operand is suitable as the source operand +;; for a logic or arithmeitc instruction. Registers, integers +;; and a restricted subset of memory addresses are allowed. + +(define_predicate "rx_source_operand" + (match_code "const_int,reg,mem") + { + if (CONST_INT_P (op)) + return rx_is_legitimate_constant (op); + + if (! MEM_P (op)) + return true; + + /* Do not allow size conversions whilst accessing memory. */ + if (GET_MODE (op) != mode) + return false; + + return rx_is_restricted_memory_address (XEXP (op, 0), mode); + } +) + +;; Check that the operand is suitable as the source operand +;; for a comparison instruction. This is the same as +;; rx_source_operand except that SUBREGs are allowed but +;; CONST_INTs are not. + +(define_predicate "rx_compare_operand" + (match_code "subreg,reg,mem") + { + if (GET_CODE (op) == SUBREG) + return REG_P (XEXP (op, 0)); + + if (! MEM_P (op)) + return true; + + return rx_is_restricted_memory_address (XEXP (op, 0), mode); + } +) + +;; Return true if OP is a store multiple operation. This looks like: +;; +;; [(set (SP) (MINUS (SP) (INT))) +;; (set (MEM (SP)) (REG)) +;; (set (MEM (MINUS (SP) (INT))) (REG)) {optionally repeated} +;; ] + +(define_special_predicate "rx_store_multiple_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int src_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != MINUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! REG_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || ! MEM_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS + || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1)) + != GET_MODE_SIZE (SImode)) + return false; + + src_regno = REGNO (SET_SRC (element)); + + /* Check that the remaining elements use SP- + addressing and decreasing register numbers. */ + for (i = 2; i < count; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || REGNO (SET_SRC (element)) != src_regno - (i - 1) + || ! MEM_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || GET_CODE (XEXP (SET_DEST (element), 0)) != MINUS + || ! REG_P (XEXP (XEXP (SET_DEST (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_DEST (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_DEST (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_DEST (element), 0), 1)) + != i * GET_MODE_SIZE (SImode)) + return false; + } + return true; +}) + +;; Return true if OP is a load multiple operation. +;; This looks like: +;; [(set (SP) (PLUS (SP) (INT))) +;; (set (REG) (MEM (SP))) +;; (set (REG) (MEM (PLUS (SP) (INT)))) {optionally repeated} +;; ] + +(define_special_predicate "rx_load_multiple_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != PLUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || ! MEM_P (SET_SRC (element)) + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG) + return false; + + dest_regno = REGNO (SET_DEST (element)); + + /* Check that the remaining elements use SP+ + addressing and incremental register numbers. */ + for (i = 2; i < count; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || REGNO (SET_DEST (element)) != dest_regno + (i - 1) + || ! MEM_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS + || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + return true; +}) + +;; Return true if OP is a pop-and-return load multiple operation. +;; This looks like: +;; [(set (SP) (PLUS (SP) (INT))) +;; (set (REG) (MEM (SP))) +;; (set (REG) (MEM (PLUS (SP) (INT)))) {optional and possibly repeated} +;; (return) +;; ] + +(define_special_predicate "rx_rtsd_vector" + (match_code "parallel") +{ + int count = XVECLEN (op, 0); + unsigned int dest_regno; + rtx element; + int i; + + /* Perform a quick check so we don't blow up below. */ + if (count <= 2) + return false; + + /* Check that the first element of the vector is the stack adjust. */ + element = XVECEXP (op, 0, 0); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || REGNO (SET_DEST (element)) != SP_REG + || GET_CODE (SET_SRC (element)) != PLUS + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG + || ! CONST_INT_P (XEXP (SET_SRC (element), 1))) + return false; + + /* Check that the next element is the first push. */ + element = XVECEXP (op, 0, 1); + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || ! MEM_P (SET_SRC (element)) + || ! REG_P (XEXP (SET_SRC (element), 0)) + || REGNO (XEXP (SET_SRC (element), 0)) != SP_REG) + return false; + + dest_regno = REGNO (SET_DEST (element)); + + /* Check that the remaining elements, if any, and except + for the last one, use SP+ addressing and incremental + register numbers. */ + for (i = 2; i < count - 1; i++) + { + element = XVECEXP (op, 0, i); + + if ( ! SET_P (element) + || ! REG_P (SET_DEST (element)) + || GET_MODE (SET_DEST (element)) != SImode + || REGNO (SET_DEST (element)) != dest_regno + (i - 1) + || ! MEM_P (SET_SRC (element)) + || GET_MODE (SET_SRC (element)) != SImode + || GET_CODE (XEXP (SET_SRC (element), 0)) != PLUS + || ! REG_P (XEXP (XEXP (SET_SRC (element), 0), 0)) + || REGNO (XEXP (XEXP (SET_SRC (element), 0), 0)) != SP_REG + || ! CONST_INT_P (XEXP (XEXP (SET_SRC (element), 0), 1)) + || INTVAL (XEXP (XEXP (SET_SRC (element), 0), 1)) + != (i - 1) * GET_MODE_SIZE (SImode)) + return false; + } + + /* The last element must be a RETURN. */ + element = XVECEXP (op, 0, count - 1); + return GET_CODE (element) == RETURN; +}) diff --git a/gcc/config/rx/rx-protos.h b/gcc/config/rx/rx-protos.h new file mode 100644 index 00000000000..5c37fe0a83c --- /dev/null +++ b/gcc/config/rx/rx-protos.h @@ -0,0 +1,52 @@ +/* Exported function prototypes from the Renesas RX backend. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + . */ + +#ifndef GCC_RX_PROTOS_H +#define GCC_RX_PROTOS_H + +/* A few abbreviations to make the prototypes shorter. */ +#define Mmode enum machine_mode +#define Fargs CUMULATIVE_ARGS + +extern void rx_conditional_register_usage (void); +extern void rx_expand_prologue (void); +extern int rx_initial_elimination_offset (int, int); + +#ifdef RTX_CODE +extern void rx_emit_stack_popm (rtx *, bool); +extern void rx_emit_stack_pushm (rtx *); +extern void rx_expand_epilogue (bool); +extern bool rx_expand_insv (rtx *); +extern const char * rx_gen_cond_branch_template (rtx, bool); +extern char * rx_gen_move_template (rtx *, bool); +extern bool rx_is_legitimate_constant (rtx); +extern bool rx_is_mode_dependent_addr (rtx); +extern bool rx_is_restricted_memory_address (rtx, Mmode); +extern void rx_notice_update_cc (rtx body, rtx insn); +extern void rx_print_operand (FILE *, rtx, int); +extern void rx_print_operand_address (FILE *, rtx); +#endif + +#ifdef TREE_CODE +extern unsigned int rx_function_arg_size (Mmode, const_tree); +extern struct rtx_def * rx_function_arg (Fargs *, Mmode, const_tree, bool); +#endif + +#endif /* GCC_RX_PROTOS_H */ diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c new file mode 100644 index 00000000000..885f52581de --- /dev/null +++ b/gcc/config/rx/rx.c @@ -0,0 +1,2517 @@ +/* Subroutines used for code generation on Renesas RX processors. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + . */ + +/* To Do: + + * Re-enable memory-to-memory copies and fix up reload. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "rtl.h" +#include "regs.h" +#include "hard-reg-set.h" +#include "real.h" +#include "insn-config.h" +#include "conditions.h" +#include "output.h" +#include "insn-attr.h" +#include "flags.h" +#include "function.h" +#include "expr.h" +#include "optabs.h" +#include "libfuncs.h" +#include "recog.h" +#include "toplev.h" +#include "reload.h" +#include "df.h" +#include "ggc.h" +#include "tm_p.h" +#include "debug.h" +#include "target.h" +#include "target-def.h" +#include "langhooks.h" + +enum rx_cpu_types rx_cpu_type = RX600; + +/* Return true if OP is a reference to an object in a small data area. */ + +static bool +rx_small_data_operand (rtx op) +{ + if (rx_small_data_limit == 0) + return false; + + if (GET_CODE (op) == SYMBOL_REF) + return SYMBOL_REF_SMALL_P (op); + + return false; +} + +static bool +rx_is_legitimate_address (Mmode mode, rtx x, bool strict ATTRIBUTE_UNUSED) +{ + if (RTX_OK_FOR_BASE (x, strict)) + /* Register Indirect. */ + return true; + + if (GET_MODE_SIZE (mode) == 4 + && (GET_CODE (x) == PRE_DEC || GET_CODE (x) == POST_INC)) + /* Pre-decrement Register Indirect or + Post-increment Register Indirect. */ + return RTX_OK_FOR_BASE (XEXP (x, 0), strict); + + if (GET_CODE (x) == PLUS) + { + rtx arg1 = XEXP (x, 0); + rtx arg2 = XEXP (x, 1); + rtx index = NULL_RTX; + + if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, strict)) + index = arg2; + else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, strict)) + index = arg1; + else + return false; + + switch (GET_CODE (index)) + { + case CONST_INT: + { + /* Register Relative: REG + INT. + Only positive, mode-aligned, mode-sized + displacements are allowed. */ + HOST_WIDE_INT val = INTVAL (index); + int factor; + + if (val < 0) + return false; + + switch (GET_MODE_SIZE (mode)) + { + default: + case 4: factor = 4; break; + case 2: factor = 2; break; + case 1: factor = 1; break; + } + + if (val > (65535 * factor)) + return false; + return (val % factor) == 0; + } + + case REG: + /* Unscaled Indexed Register Indirect: REG + REG + Size has to be "QI", REG has to be valid. */ + return GET_MODE_SIZE (mode) == 1 && RTX_OK_FOR_BASE (index, strict); + + case MULT: + { + /* Scaled Indexed Register Indirect: REG + (REG * FACTOR) + Factor has to equal the mode size, REG has to be valid. */ + rtx factor; + + factor = XEXP (index, 1); + index = XEXP (index, 0); + + return REG_P (index) + && RTX_OK_FOR_BASE (index, strict) + && CONST_INT_P (factor) + && GET_MODE_SIZE (mode) == INTVAL (factor); + } + + default: + return false; + } + } + + /* Small data area accesses turn into register relative offsets. */ + return rx_small_data_operand (x); +} + +/* Returns TRUE for simple memory addreses, ie ones + that do not involve register indirect addressing + or pre/post increment/decrement. */ + +bool +rx_is_restricted_memory_address (rtx mem, enum machine_mode mode) +{ + rtx base, index; + + if (! rx_is_legitimate_address + (mode, mem, reload_in_progress || reload_completed)) + return false; + + switch (GET_CODE (mem)) + { + case REG: + /* Simple memory addresses are OK. */ + return true; + + case PRE_DEC: + case POST_INC: + return false; + + case PLUS: + /* Only allow REG+INT addressing. */ + base = XEXP (mem, 0); + index = XEXP (mem, 1); + + return RX_REG_P (base) && CONST_INT_P (index); + + case SYMBOL_REF: + /* Can happen when small data is being supported. + Assume that it will be resolved into GP+INT. */ + return true; + + default: + gcc_unreachable (); + } +} + +bool +rx_is_mode_dependent_addr (rtx addr) +{ + if (GET_CODE (addr) == CONST) + addr = XEXP (addr, 0); + + switch (GET_CODE (addr)) + { + /* --REG and REG++ only work in SImode. */ + case PRE_DEC: + case POST_INC: + return true; + + case MINUS: + case PLUS: + if (! REG_P (XEXP (addr, 0))) + return true; + + addr = XEXP (addr, 1); + + switch (GET_CODE (addr)) + { + case REG: + /* REG+REG only works in SImode. */ + return true; + + case CONST_INT: + /* REG+INT is only mode independent if INT is a + multiple of 4, positive and will fit into 8-bits. */ + if (((INTVAL (addr) & 3) == 0) + && IN_RANGE (INTVAL (addr), 4, 252)) + return false; + return true; + + case SYMBOL_REF: + case LABEL_REF: + return true; + + case MULT: + gcc_assert (REG_P (XEXP (addr, 0))); + gcc_assert (CONST_INT_P (XEXP (addr, 1))); + /* REG+REG*SCALE is always mode dependent. */ + return true; + + default: + /* Not recognized, so treat as mode dependent. */ + return true; + } + + case CONST_INT: + case SYMBOL_REF: + case LABEL_REF: + case REG: + /* These are all mode independent. */ + return false; + + default: + /* Everything else is unrecognized, + so treat as mode dependent. */ + return true; + } +} + +/* A C compound statement to output to stdio stream FILE the + assembler syntax for an instruction operand that is a memory + reference whose address is ADDR. */ + +void +rx_print_operand_address (FILE * file, rtx addr) +{ + switch (GET_CODE (addr)) + { + case REG: + fprintf (file, "["); + rx_print_operand (file, addr, 0); + fprintf (file, "]"); + break; + + case PRE_DEC: + fprintf (file, "[-"); + rx_print_operand (file, XEXP (addr, 0), 0); + fprintf (file, "]"); + break; + + case POST_INC: + fprintf (file, "["); + rx_print_operand (file, XEXP (addr, 0), 0); + fprintf (file, "+]"); + break; + + case PLUS: + { + rtx arg1 = XEXP (addr, 0); + rtx arg2 = XEXP (addr, 1); + rtx base, index; + + if (REG_P (arg1) && RTX_OK_FOR_BASE (arg1, true)) + base = arg1, index = arg2; + else if (REG_P (arg2) && RTX_OK_FOR_BASE (arg2, true)) + base = arg2, index = arg1; + else + { + rx_print_operand (file, arg1, 0); + fprintf (file, " + "); + rx_print_operand (file, arg2, 0); + break; + } + + if (REG_P (index) || GET_CODE (index) == MULT) + { + fprintf (file, "["); + rx_print_operand (file, index, 'A'); + fprintf (file, ","); + } + else /* GET_CODE (index) == CONST_INT */ + { + rx_print_operand (file, index, 'A'); + fprintf (file, "["); + } + rx_print_operand (file, base, 0); + fprintf (file, "]"); + break; + } + + case LABEL_REF: + case SYMBOL_REF: + case CONST: + fprintf (file, "#"); + default: + output_addr_const (file, addr); + break; + } +} + +static void +rx_print_integer (FILE * file, HOST_WIDE_INT val) +{ + if (IN_RANGE (val, -64, 64)) + fprintf (file, HOST_WIDE_INT_PRINT_DEC, val); + else + fprintf (file, + TARGET_AS100_SYNTAX + ? "0%" HOST_WIDE_INT_PRINT "xH" : HOST_WIDE_INT_PRINT_HEX, + val); +} + +static bool +rx_assemble_integer (rtx x, unsigned int size, int is_aligned) +{ + const char * op = integer_asm_op (size, is_aligned); + + if (! CONST_INT_P (x)) + return default_assemble_integer (x, size, is_aligned); + + if (op == NULL) + return false; + fputs (op, asm_out_file); + + rx_print_integer (asm_out_file, INTVAL (x)); + fputc ('\n', asm_out_file); + return true; +} + + +int rx_float_compare_mode; + +/* Handles the insertion of a single operand into the assembler output. + The % directives supported are: + + %A Print an operand without a leading # character. + %B Print an integer comparison name. + %C Print a control register name. + %F Print a condition code flag name. + %H Print high part of a DImode register, integer or address. + %L Print low part of a DImode register, integer or address. + %Q If the operand is a MEM, then correctly generate + register indirect or register relative addressing. */ + +void +rx_print_operand (FILE * file, rtx op, int letter) +{ + switch (letter) + { + case 'A': + /* Print an operand without a leading #. */ + if (MEM_P (op)) + op = XEXP (op, 0); + + switch (GET_CODE (op)) + { + case LABEL_REF: + case SYMBOL_REF: + output_addr_const (file, op); + break; + case CONST_INT: + fprintf (file, "%ld", (long) INTVAL (op)); + break; + default: + rx_print_operand (file, op, 0); + break; + } + break; + + case 'B': + switch (GET_CODE (op)) + { + case LT: fprintf (file, "lt"); break; + case GE: fprintf (file, "ge"); break; + case GT: fprintf (file, "gt"); break; + case LE: fprintf (file, "le"); break; + case GEU: fprintf (file, "geu"); break; + case LTU: fprintf (file, "ltu"); break; + case GTU: fprintf (file, "gtu"); break; + case LEU: fprintf (file, "leu"); break; + case EQ: fprintf (file, "eq"); break; + case NE: fprintf (file, "ne"); break; + default: debug_rtx (op); gcc_unreachable (); + } + break; + + case 'C': + gcc_assert (CONST_INT_P (op)); + switch (INTVAL (op)) + { + case 0: fprintf (file, "psw"); break; + case 2: fprintf (file, "usp"); break; + case 3: fprintf (file, "fpsw"); break; + case 4: fprintf (file, "cpen"); break; + case 8: fprintf (file, "bpsw"); break; + case 9: fprintf (file, "bpc"); break; + case 0xa: fprintf (file, "isp"); break; + case 0xb: fprintf (file, "fintv"); break; + case 0xc: fprintf (file, "intb"); break; + default: + gcc_unreachable (); + } + break; + + case 'F': + gcc_assert (CONST_INT_P (op)); + switch (INTVAL (op)) + { + case 0: case 'c': case 'C': fprintf (file, "C"); break; + case 1: case 'z': case 'Z': fprintf (file, "Z"); break; + case 2: case 's': case 'S': fprintf (file, "S"); break; + case 3: case 'o': case 'O': fprintf (file, "O"); break; + case 8: case 'i': case 'I': fprintf (file, "I"); break; + case 9: case 'u': case 'U': fprintf (file, "U"); break; + default: + gcc_unreachable (); + } + break; + + case 'H': + if (REG_P (op)) + fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 0 : 1)]); + else if (CONST_INT_P (op)) + { + HOST_WIDE_INT v = INTVAL (op); + + fprintf (file, "#"); + /* Trickery to avoid problems with shifting 32 bits at a time. */ + v = v >> 16; + v = v >> 16; + rx_print_integer (file, v); + } + else + { + gcc_assert (MEM_P (op)); + + if (! WORDS_BIG_ENDIAN) + op = adjust_address (op, SImode, 4); + output_address (XEXP (op, 0)); + } + break; + + case 'L': + if (REG_P (op)) + fprintf (file, "%s", reg_names [REGNO (op) + (WORDS_BIG_ENDIAN ? 1 : 0)]); + else if (CONST_INT_P (op)) + { + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op) & 0xffffffff); + } + else + { + gcc_assert (MEM_P (op)); + + if (WORDS_BIG_ENDIAN) + op = adjust_address (op, SImode, 4); + output_address (XEXP (op, 0)); + } + break; + + case 'Q': + if (MEM_P (op)) + { + HOST_WIDE_INT offset; + + op = XEXP (op, 0); + + if (REG_P (op)) + offset = 0; + else if (GET_CODE (op) == PLUS) + { + rtx displacement; + + if (REG_P (XEXP (op, 0))) + { + displacement = XEXP (op, 1); + op = XEXP (op, 0); + } + else + { + displacement = XEXP (op, 0); + op = XEXP (op, 1); + gcc_assert (REG_P (op)); + } + + gcc_assert (CONST_INT_P (displacement)); + offset = INTVAL (displacement); + gcc_assert (offset >= 0); + + fprintf (file, "%ld", offset); + } + else + gcc_unreachable (); + + fprintf (file, "["); + rx_print_operand (file, op, 0); + fprintf (file, "]."); + + switch (GET_MODE_SIZE (GET_MODE (op))) + { + case 1: + gcc_assert (offset < 65535 * 1); + fprintf (file, "B"); + break; + case 2: + gcc_assert (offset % 2 == 0); + gcc_assert (offset < 65535 * 2); + fprintf (file, "W"); + break; + default: + gcc_assert (offset % 4 == 0); + gcc_assert (offset < 65535 * 4); + fprintf (file, "L"); + break; + } + break; + } + + /* Fall through. */ + + default: + switch (GET_CODE (op)) + { + case MULT: + /* Should be the scaled part of an + indexed register indirect address. */ + { + rtx base = XEXP (op, 0); + rtx index = XEXP (op, 1); + + /* Check for a swaped index register and scaling factor. + Not sure if this can happen, but be prepared to handle it. */ + if (CONST_INT_P (base) && REG_P (index)) + { + rtx tmp = base; + base = index; + index = tmp; + } + + gcc_assert (REG_P (base)); + gcc_assert (REGNO (base) < FIRST_PSEUDO_REGISTER); + gcc_assert (CONST_INT_P (index)); + /* Do not try to verify the value of the scalar as it is based + on the mode of the MEM not the mode of the MULT. (Which + will always be SImode). */ + fprintf (file, "%s", reg_names [REGNO (base)]); + break; + } + + case MEM: + output_address (XEXP (op, 0)); + break; + + case PLUS: + output_address (op); + break; + + case REG: + gcc_assert (REGNO (op) < FIRST_PSEUDO_REGISTER); + fprintf (file, "%s", reg_names [REGNO (op)]); + break; + + case SUBREG: + gcc_assert (subreg_regno (op) < FIRST_PSEUDO_REGISTER); + fprintf (file, "%s", reg_names [subreg_regno (op)]); + break; + + /* This will only be single precision.... */ + case CONST_DOUBLE: + { + unsigned long val; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, op); + REAL_VALUE_TO_TARGET_SINGLE (rv, val); + fprintf (file, TARGET_AS100_SYNTAX ? "#0%lxH" : "#0x%lx", val); + break; + } + + case CONST_INT: + fprintf (file, "#"); + rx_print_integer (file, INTVAL (op)); + break; + + case SYMBOL_REF: + case CONST: + case LABEL_REF: + case CODE_LABEL: + case UNSPEC: + rx_print_operand_address (file, op); + break; + + default: + gcc_unreachable (); + } + break; + } +} + +/* Returns an assembler template for a move instruction. */ + +char * +rx_gen_move_template (rtx * operands, bool is_movu) +{ + static char template [64]; + const char * extension = TARGET_AS100_SYNTAX ? ".L" : ""; + const char * src_template; + const char * dst_template; + rtx dest = operands[0]; + rtx src = operands[1]; + + /* Decide which extension, if any, should be given to the move instruction. */ + switch (CONST_INT_P (src) ? GET_MODE (dest) : GET_MODE (src)) + { + case QImode: + /* The .B extension is not valid when + loading an immediate into a register. */ + if (! REG_P (dest) || ! CONST_INT_P (src)) + extension = ".B"; + break; + case HImode: + if (! REG_P (dest) || ! CONST_INT_P (src)) + /* The .W extension is not valid when + loading an immediate into a register. */ + extension = ".W"; + break; + case SFmode: + case SImode: + extension = ".L"; + break; + case VOIDmode: + /* This mode is used by constants. */ + break; + default: + debug_rtx (src); + gcc_unreachable (); + } + + if (MEM_P (src) && rx_small_data_operand (XEXP (src, 0))) + src_template = "%%gp(%A1)[r13]"; + else + src_template = "%1"; + + if (MEM_P (dest) && rx_small_data_operand (XEXP (dest, 0))) + dst_template = "%%gp(%A0)[r13]"; + else + dst_template = "%0"; + + sprintf (template, "%s%s\t%s, %s", is_movu ? "movu" : "mov", + extension, src_template, dst_template); + return template; +} + +/* Returns an assembler template for a conditional branch instruction. */ + +const char * +rx_gen_cond_branch_template (rtx condition, bool reversed) +{ + enum rtx_code code = GET_CODE (condition); + + + if ((cc_status.flags & CC_NO_OVERFLOW) && ! rx_float_compare_mode) + gcc_assert (code != GT && code != GE && code != LE && code != LT); + + if ((cc_status.flags & CC_NO_CARRY) || rx_float_compare_mode) + gcc_assert (code != GEU && code != GTU && code != LEU && code != LTU); + + if (reversed) + { + if (rx_float_compare_mode) + code = reverse_condition_maybe_unordered (code); + else + code = reverse_condition (code); + } + + /* We do not worry about encoding the branch length here as GAS knows + how to choose the smallest version, and how to expand a branch that + is to a destination that is out of range. */ + + switch (code) + { + case UNEQ: return "bo\t1f\n\tbeq\t%0\n1:"; + case LTGT: return "bo\t1f\n\tbne\t%0\n1:"; + case UNLT: return "bo\t1f\n\tbn\t%0\n1:"; + case UNGE: return "bo\t1f\n\tbpz\t%0\n1:"; + case UNLE: return "bo\t1f\n\tbgt\t1f\n\tbra\t%0\n1:"; + case UNGT: return "bo\t1f\n\tble\t1f\n\tbra\t%0\n1:"; + case UNORDERED: return "bo\t%0"; + case ORDERED: return "bno\t%0"; + + case LT: return rx_float_compare_mode ? "bn\t%0" : "blt\t%0"; + case GE: return rx_float_compare_mode ? "bpz\t%0" : "bge\t%0"; + case GT: return "bgt\t%0"; + case LE: return "ble\t%0"; + case GEU: return "bgeu\t%0"; + case LTU: return "bltu\t%0"; + case GTU: return "bgtu\t%0"; + case LEU: return "bleu\t%0"; + case EQ: return "beq\t%0"; + case NE: return "bne\t%0"; + default: + gcc_unreachable (); + } +} + +/* Return VALUE rounded up to the next ALIGNMENT boundary. */ + +static inline unsigned int +rx_round_up (unsigned int value, unsigned int alignment) +{ + alignment -= 1; + return (value + alignment) & (~ alignment); +} + +/* Return the number of bytes in the argument registers + occupied by an argument of type TYPE and mode MODE. */ + +unsigned int +rx_function_arg_size (Mmode mode, const_tree type) +{ + unsigned int num_bytes; + + num_bytes = (mode == BLKmode) + ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + return rx_round_up (num_bytes, UNITS_PER_WORD); +} + +#define NUM_ARG_REGS 4 +#define MAX_NUM_ARG_BYTES (NUM_ARG_REGS * UNITS_PER_WORD) + +/* Return an RTL expression describing the register holding a function + parameter of mode MODE and type TYPE or NULL_RTX if the parameter should + be passed on the stack. CUM describes the previous parameters to the + function and NAMED is false if the parameter is part of a variable + parameter list, or the last named parameter before the start of a + variable parameter list. */ + +rtx +rx_function_arg (Fargs * cum, Mmode mode, const_tree type, bool named) +{ + unsigned int next_reg; + unsigned int bytes_so_far = *cum; + unsigned int size; + unsigned int rounded_size; + + /* An exploded version of rx_function_arg_size. */ + size = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode); + + rounded_size = rx_round_up (size, UNITS_PER_WORD); + + /* Don't pass this arg via registers if there + are insufficient registers to hold all of it. */ + if (rounded_size + bytes_so_far > MAX_NUM_ARG_BYTES) + return NULL_RTX; + + /* Unnamed arguments and the last named argument in a + variadic function are always passed on the stack. */ + if (!named) + return NULL_RTX; + + /* Structures must occupy an exact number of registers, + otherwise they are passed on the stack. */ + if ((type == NULL || AGGREGATE_TYPE_P (type)) + && (size % UNITS_PER_WORD) != 0) + return NULL_RTX; + + next_reg = (bytes_so_far / UNITS_PER_WORD) + 1; + + return gen_rtx_REG (mode, next_reg); +} + +/* Return an RTL describing where a function return value of type RET_TYPE + is held. */ + +static rtx +rx_function_value (const_tree ret_type, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (TYPE_MODE (ret_type), FUNC_RETURN_REGNUM); +} + +static bool +rx_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) +{ + HOST_WIDE_INT size; + + if (TYPE_MODE (type) != BLKmode + && ! AGGREGATE_TYPE_P (type)) + return false; + + size = int_size_in_bytes (type); + /* Large structs and those whose size is not an + exact multiple of 4 are returned in memory. */ + return size < 1 + || size > 16 + || (size % UNITS_PER_WORD) != 0; +} + +static rtx +rx_struct_value_rtx (tree fndecl ATTRIBUTE_UNUSED, + int incoming ATTRIBUTE_UNUSED) +{ + return gen_rtx_REG (Pmode, STRUCT_VAL_REGNUM); +} + +static bool +rx_return_in_msb (const_tree valtype) +{ + return TARGET_BIG_ENDIAN_DATA + && (AGGREGATE_TYPE_P (valtype) || TREE_CODE (valtype) == COMPLEX_TYPE); +} + +/* Returns true if the provided function has the specified attribute. */ + +static inline bool +has_func_attr (const_tree decl, const char * func_attr) +{ + if (decl == NULL_TREE) + decl = current_function_decl; + + return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE; +} + +/* Returns true if the provided function has the "fast_interrupt" attribute. */ + +static inline bool +is_fast_interrupt_func (const_tree decl) +{ + return has_func_attr (decl, "fast_interrupt"); +} + +/* Returns true if the provided function has the "interrupt" attribute. */ + +static inline bool +is_interrupt_func (const_tree decl) +{ + return has_func_attr (decl, "interrupt"); +} + +/* Returns true if the provided function has the "naked" attribute. */ + +static inline bool +is_naked_func (const_tree decl) +{ + return has_func_attr (decl, "naked"); +} + +static bool use_fixed_regs = false; + +void +rx_conditional_register_usage (void) +{ + static bool using_fixed_regs = false; + + if (rx_small_data_limit > 0) + fixed_regs[GP_BASE_REGNUM] = call_used_regs [GP_BASE_REGNUM] = 1; + + if (use_fixed_regs != using_fixed_regs) + { + static char saved_fixed_regs[FIRST_PSEUDO_REGISTER]; + static char saved_call_used_regs[FIRST_PSEUDO_REGISTER]; + + if (use_fixed_regs) + { + unsigned int switched = 0; + unsigned int r; + + /* This is for fast interrupt handlers. Any register in + the range r10 to r13 (inclusive) that is currently + marked as fixed is now a viable, call-saved register. + All other registers are fixed. */ + memcpy (saved_fixed_regs, fixed_regs, sizeof fixed_regs); + memcpy (saved_call_used_regs, call_used_regs, sizeof call_used_regs); + + for (r = 1; r < 10; r++) + fixed_regs[r] = call_used_regs[r] = 1; + + for (r = 10; r <= 13; r++) + if (fixed_regs[r]) + { + fixed_regs[r] = 0; + call_used_regs[r] = 1; + ++ switched; + } + else + { + fixed_regs[r] = 1; + call_used_regs[r] = 1; + } + + fixed_regs[14] = call_used_regs[14] = 1; + fixed_regs[15] = call_used_regs[15] = 1; + + if (switched == 0) + { + static bool warned = false; + + if (! warned) + { + warning (0, "no fixed registers available " + "for use by fast interrupt handler"); + warned = true; + } + } + } + else + { + /* Restore the normal register masks. */ + memcpy (fixed_regs, saved_fixed_regs, sizeof fixed_regs); + memcpy (call_used_regs, saved_call_used_regs, sizeof call_used_regs); + } + + using_fixed_regs = use_fixed_regs; + } +} + +/* Perform any actions necessary before starting to compile FNDECL. + For the RX we use this to make sure that we have the correct + set of register masks selected. If FNDECL is NULL then we are + compiling top level things. */ + +static void +rx_set_current_function (tree fndecl) +{ + /* Remember the last target of rx_set_current_function. */ + static tree rx_previous_fndecl; + bool prev_was_fast_interrupt; + bool current_is_fast_interrupt; + + /* Only change the context if the function changes. This hook is called + several times in the course of compiling a function, and we don't want + to slow things down too much or call target_reinit when it isn't safe. */ + if (fndecl == rx_previous_fndecl) + return; + + prev_was_fast_interrupt + = rx_previous_fndecl + ? is_fast_interrupt_func (rx_previous_fndecl) : false; + + current_is_fast_interrupt + = fndecl ? is_fast_interrupt_func (fndecl) : false; + + if (prev_was_fast_interrupt != current_is_fast_interrupt) + { + use_fixed_regs = current_is_fast_interrupt; + target_reinit (); + } + + rx_previous_fndecl = fndecl; +} + +/* Typical stack layout should looks like this after the function's prologue: + + | | + -- ^ + | | \ | + | | arguments saved | Increasing + | | on the stack | addresses + PARENT arg pointer -> | | / + -------------------------- ---- ------------------- + CHILD |ret | return address + -- + | | \ + | | call saved + | | registers + | | / + -- + | | \ + | | local + | | variables + frame pointer -> | | / + -- + | | \ + | | outgoing | Decreasing + | | arguments | addresses + current stack pointer -> | | / | + -------------------------- ---- ------------------ V + | | */ + +static unsigned int +bit_count (unsigned int x) +{ + const unsigned int m1 = 0x55555555; + const unsigned int m2 = 0x33333333; + const unsigned int m4 = 0x0f0f0f0f; + + x -= (x >> 1) & m1; + x = (x & m2) + ((x >> 2) & m2); + x = (x + (x >> 4)) & m4; + x += x >> 8; + + return (x + (x >> 16)) & 0x3f; +} + +/* Returns either the lowest numbered and highest numbered registers that + occupy the call-saved area of the stack frame, if the registers are + stored as a contiguous block, or else a bitmask of the individual + registers if they are stored piecemeal. + + Also computes the size of the frame and the size of the outgoing + arguments block (in bytes). */ + +static void +rx_get_stack_layout (unsigned int * lowest, + unsigned int * highest, + unsigned int * register_mask, + unsigned int * frame_size, + unsigned int * stack_size) +{ + unsigned int reg; + unsigned int low; + unsigned int high; + unsigned int fixed_reg = 0; + unsigned int save_mask; + unsigned int pushed_mask; + unsigned int unneeded_pushes; + + if (is_naked_func (NULL_TREE) + || is_fast_interrupt_func (NULL_TREE)) + { + /* Naked functions do not create their own stack frame. + Instead the programmer must do that for us. + + Fast interrupt handlers use fixed registers that have + been epsecially released to the function, so they do + not need or want a stack frame. */ + * lowest = 0; + * highest = 0; + * register_mask = 0; + * frame_size = 0; + * stack_size = 0; + return; + } + + for (save_mask = high = low = 0, reg = 1; reg < FIRST_PSEUDO_REGISTER; reg++) + { + if (df_regs_ever_live_p (reg) + && (! call_used_regs[reg] + /* Even call clobbered registered must + be pushed inside interrupt handlers. */ + || is_interrupt_func (NULL_TREE))) + { + if (low == 0) + low = reg; + high = reg; + + save_mask |= 1 << reg; + } + + /* Remember if we see a fixed register + after having found the low register. */ + if (low != 0 && fixed_reg == 0 && fixed_regs [reg]) + fixed_reg = reg; + } + + /* Decide if it would be faster fill in the call-saved area of the stack + frame using multiple PUSH instructions instead of a single PUSHM + instruction. + + SAVE_MASK is a bitmask of the registers that must be stored in the + call-save area. PUSHED_MASK is a bitmask of the registers that would + be pushed into the area if we used a PUSHM instruction. UNNEEDED_PUSHES + is a bitmask of those registers in pushed_mask that are not in + save_mask. + + We use a simple heuristic that says that it is better to use + multiple PUSH instructions if the number of unnecessary pushes is + greater than the number of necessary pushes. + + We also use multiple PUSH instructions if there are any fixed registers + between LOW and HIGH. The only way that this can happen is if the user + has specified --fixed- on the command line and in such + circumstances we do not want to touch the fixed registers at all. + + FIXME: Is it worth improving this heuristic ? */ + pushed_mask = (-1 << low) & ~(-1 << (high + 1)); + unneeded_pushes = (pushed_mask & (~ save_mask)) & pushed_mask; + + if ((fixed_reg && fixed_reg <= high) + || (optimize_function_for_speed_p (cfun) + && bit_count (save_mask) < bit_count (unneeded_pushes))) + { + /* Use multiple pushes. */ + * lowest = 0; + * highest = 0; + * register_mask = save_mask; + } + else + { + /* Use one push multiple instruction. */ + * lowest = low; + * highest = high; + * register_mask = 0; + } + + * frame_size = rx_round_up + (get_frame_size (), STACK_BOUNDARY / BITS_PER_UNIT); + + if (crtl->args.size > 0) + * frame_size += rx_round_up + (crtl->args.size, STACK_BOUNDARY / BITS_PER_UNIT); + + * stack_size = rx_round_up + (crtl->outgoing_args_size, STACK_BOUNDARY / BITS_PER_UNIT); +} + +/* Generate a PUSHM instruction that matches the given operands. */ + +void +rx_emit_stack_pushm (rtx * operands) +{ + HOST_WIDE_INT last_reg; + rtx first_push; + + gcc_assert (CONST_INT_P (operands[0])); + last_reg = (INTVAL (operands[0]) / UNITS_PER_WORD) - 1; + + gcc_assert (GET_CODE (operands[1]) == PARALLEL); + first_push = XVECEXP (operands[1], 0, 1); + gcc_assert (SET_P (first_push)); + first_push = SET_SRC (first_push); + gcc_assert (REG_P (first_push)); + + asm_fprintf (asm_out_file, "\tpushm\t%s-%s\n", + reg_names [REGNO (first_push) - last_reg], + reg_names [REGNO (first_push)]); +} + +/* Generate a PARALLEL that will pass the rx_store_multiple_vector predicate. */ + +static rtx +gen_rx_store_vector (unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int count = (high - low) + 2; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + gen_rtx_MINUS (SImode, stack_pointer_rtx, + GEN_INT ((count - 1) * UNITS_PER_WORD))); + + for (i = 0; i < count - 1; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_MEM (SImode, + gen_rtx_MINUS (SImode, stack_pointer_rtx, + GEN_INT ((i + 1) * UNITS_PER_WORD))), + gen_rtx_REG (SImode, high - i)); + return vector; +} + +/* Mark INSN as being frame related. If it is a PARALLEL + then mark each element as being frame related as well. */ + +static void +mark_frame_related (rtx insn) +{ + RTX_FRAME_RELATED_P (insn) = 1; + insn = PATTERN (insn); + + if (GET_CODE (insn) == PARALLEL) + { + unsigned int i; + + for (i = 0; i < XVECLEN (insn, 0); i++) + RTX_FRAME_RELATED_P (XVECEXP (insn, 0, i)) = 1; + } +} + +void +rx_expand_prologue (void) +{ + unsigned int stack_size; + unsigned int frame_size; + unsigned int mask; + unsigned int low; + unsigned int high; + unsigned int reg; + rtx insn; + + /* Naked functions use their own, programmer provided prologues. */ + if (is_naked_func (NULL_TREE) + /* Fast interrupt functions never use the stack. */ + || is_fast_interrupt_func (NULL_TREE)) + return; + + rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size); + + /* If we use any of the callee-saved registers, save them now. */ + if (mask) + { + /* Push registers in reverse order. */ + for (reg = FIRST_PSEUDO_REGISTER; reg --;) + if (mask & (1 << reg)) + { + insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, reg))); + mark_frame_related (insn); + } + } + else if (low) + { + if (high == low) + insn = emit_insn (gen_stack_push (gen_rtx_REG (SImode, low))); + else + insn = emit_insn (gen_stack_pushm (GEN_INT (((high - low) + 1) + * UNITS_PER_WORD), + gen_rx_store_vector (low, high))); + mark_frame_related (insn); + } + + if (is_interrupt_func (NULL_TREE) && TARGET_SAVE_ACC_REGISTER) + { + unsigned int acc_high, acc_low; + + /* Interrupt handlers have to preserve the accumulator + register if so requested by the user. Use the first + two pushed register as intermediaries. */ + if (mask) + { + acc_low = acc_high = 0; + + for (reg = 1; reg < FIRST_PSEUDO_REGISTER; reg ++) + if (mask & (1 << reg)) + { + if (acc_low == 0) + acc_low = reg; + else + { + acc_high = reg; + break; + } + } + + /* We have assumed that there are at least two registers pushed... */ + gcc_assert (acc_high != 0); + + /* Note - the bottom 16 bits of the accumulator are inaccessible. + We just assume that they are zero. */ + emit_insn (gen_mvfacmi (gen_rtx_REG (SImode, acc_low))); + emit_insn (gen_mvfachi (gen_rtx_REG (SImode, acc_high))); + emit_insn (gen_stack_push (gen_rtx_REG (SImode, acc_low))); + emit_insn (gen_stack_push (gen_rtx_REG (SImode, acc_high))); + } + else + { + acc_low = low; + acc_high = low + 1; + + /* We have assumed that there are at least two registers pushed... */ + gcc_assert (acc_high <= high); + + emit_insn (gen_mvfacmi (gen_rtx_REG (SImode, acc_low))); + emit_insn (gen_mvfachi (gen_rtx_REG (SImode, acc_high))); + emit_insn (gen_stack_pushm (GEN_INT (2 * UNITS_PER_WORD), + gen_rx_store_vector (acc_low, acc_high))); + } + + frame_size += 2 * UNITS_PER_WORD; + } + + /* If needed, set up the frame pointer. */ + if (frame_pointer_needed) + { + if (frame_size) + insn = emit_insn (gen_addsi3 (frame_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size))); + else + insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx); + + RTX_FRAME_RELATED_P (insn) = 1; + } + + insn = NULL_RTX; + + /* Allocate space for the outgoing args. + If the stack frame has not already been set up then handle this as well. */ + if (stack_size) + { + if (frame_size) + { + if (frame_pointer_needed) + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, frame_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) + stack_size))); + else + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) + (frame_size + stack_size)))); + } + else + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) stack_size))); + } + else if (frame_size) + { + if (! frame_pointer_needed) + insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (- (HOST_WIDE_INT) frame_size))); + else + insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); + } + + if (insn != NULL_RTX) + RTX_FRAME_RELATED_P (insn) = 1; +} + +static void +rx_output_function_prologue (FILE * file, + HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED) +{ + if (is_fast_interrupt_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Fast Interrupt Handler\n"); + + if (is_interrupt_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Interrupt Handler\n"); + + if (is_naked_func (NULL_TREE)) + asm_fprintf (file, "\t; Note: Naked Function\n"); + + if (cfun->static_chain_decl != NULL) + asm_fprintf (file, "\t; Note: Nested function declared " + "inside another function.\n"); + + if (crtl->calls_eh_return) + asm_fprintf (file, "\t; Note: Calls __builtin_eh_return.\n"); +} + +/* Generate a POPM or RTSD instruction that matches the given operands. */ + +void +rx_emit_stack_popm (rtx * operands, bool is_popm) +{ + HOST_WIDE_INT stack_adjust; + HOST_WIDE_INT last_reg; + rtx first_push; + + gcc_assert (CONST_INT_P (operands[0])); + stack_adjust = INTVAL (operands[0]); + + gcc_assert (GET_CODE (operands[1]) == PARALLEL); + last_reg = XVECLEN (operands[1], 0) - (is_popm ? 2 : 3); + + first_push = XVECEXP (operands[1], 0, 1); + gcc_assert (SET_P (first_push)); + first_push = SET_DEST (first_push); + gcc_assert (REG_P (first_push)); + + if (is_popm) + asm_fprintf (asm_out_file, "\tpopm\t%s-%s\n", + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); + else + asm_fprintf (asm_out_file, "\trtsd\t#%d, %s-%s\n", + (int) stack_adjust, + reg_names [REGNO (first_push)], + reg_names [REGNO (first_push) + last_reg]); +} + +/* Generate a PARALLEL which will satisfy the rx_rtsd_vector predicate. */ + +static rtx +gen_rx_rtsd_vector (unsigned int adjust, unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int bias = 3; + unsigned int count = (high - low) + bias; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, adjust)); + + for (i = 0; i < count - 2; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_REG (SImode, low + i), + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : plus_constant (stack_pointer_rtx, + i * UNITS_PER_WORD))); + + XVECEXP (vector, 0, count - 1) = gen_rtx_RETURN (VOIDmode); + + return vector; +} + +/* Generate a PARALLEL which will satisfy the rx_load_multiple_vector predicate. */ + +static rtx +gen_rx_popm_vector (unsigned int low, unsigned int high) +{ + unsigned int i; + unsigned int count = (high - low) + 2; + rtx vector; + + vector = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + + XVECEXP (vector, 0, 0) = + gen_rtx_SET (SImode, stack_pointer_rtx, + plus_constant (stack_pointer_rtx, + (count - 1) * UNITS_PER_WORD)); + + for (i = 0; i < count - 1; i++) + XVECEXP (vector, 0, i + 1) = + gen_rtx_SET (SImode, + gen_rtx_REG (SImode, low + i), + gen_rtx_MEM (SImode, + i == 0 ? stack_pointer_rtx + : plus_constant (stack_pointer_rtx, + i * UNITS_PER_WORD))); + + return vector; +} + +void +rx_expand_epilogue (bool is_sibcall) +{ + unsigned int low; + unsigned int high; + unsigned int frame_size; + unsigned int stack_size; + unsigned int register_mask; + unsigned int regs_size; + unsigned int reg; + unsigned HOST_WIDE_INT total_size; + + if (is_naked_func (NULL_TREE)) + { + /* Naked functions use their own, programmer provided epilogues. + But, in order to keep gcc happy we have to generate some kind of + epilogue RTL. */ + emit_jump_insn (gen_naked_return ()); + return; + } + + rx_get_stack_layout (& low, & high, & register_mask, + & frame_size, & stack_size); + + total_size = frame_size + stack_size; + regs_size = ((high - low) + 1) * UNITS_PER_WORD; + + /* See if we are unable to use the special stack frame deconstruct and + return instructions. In most cases we can use them, but the exceptions + are: + + - Sibling calling functions deconstruct the frame but do not return to + their caller. Instead they branch to their sibling and allow their + return instruction to return to this function's parent. + + - Fast and normal interrupt handling functions have to use special + return instructions. + + - Functions where we have pushed a fragmented set of registers into the + call-save area must have the same set of registers popped. */ + if (is_sibcall + || is_fast_interrupt_func (NULL_TREE) + || is_interrupt_func (NULL_TREE) + || register_mask) + { + /* Cannot use the special instructions - deconstruct by hand. */ + if (total_size) + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size))); + + if (is_interrupt_func (NULL_TREE) && TARGET_SAVE_ACC_REGISTER) + { + unsigned int acc_low, acc_high; + + /* Reverse the saving of the accumulator register onto the stack. + Note we must adjust the saved "low" accumulator value as it + is really the middle 32-bits of the accumulator. */ + if (register_mask) + { + acc_low = acc_high = 0; + for (reg = 1; reg < FIRST_PSEUDO_REGISTER; reg ++) + if (register_mask & (1 << reg)) + { + if (acc_low == 0) + acc_low = reg; + else + { + acc_high = reg; + break; + } + } + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, acc_high))); + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, acc_low))); + } + else + { + acc_low = low; + acc_high = low + 1; + emit_insn (gen_stack_popm (GEN_INT (2 * UNITS_PER_WORD), + gen_rx_popm_vector (acc_low, acc_high))); + } + + emit_insn (gen_ashlsi3 (gen_rtx_REG (SImode, acc_low), + gen_rtx_REG (SImode, acc_low), + GEN_INT (16))); + emit_insn (gen_mvtaclo (gen_rtx_REG (SImode, acc_low))); + emit_insn (gen_mvtachi (gen_rtx_REG (SImode, acc_high))); + } + + if (register_mask) + { + for (reg = 0; reg < FIRST_PSEUDO_REGISTER; reg ++) + if (register_mask & (1 << reg)) + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, reg))); + } + else if (low) + { + if (high == low) + emit_insn (gen_stack_pop (gen_rtx_REG (SImode, low))); + else + emit_insn (gen_stack_popm (GEN_INT (regs_size), + gen_rx_popm_vector (low, high))); + } + + if (is_fast_interrupt_func (NULL_TREE)) + emit_jump_insn (gen_fast_interrupt_return ()); + else if (is_interrupt_func (NULL_TREE)) + emit_jump_insn (gen_exception_return ()); + else if (! is_sibcall) + emit_jump_insn (gen_simple_return ()); + + return; + } + + /* If we allocated space on the stack, free it now. */ + if (total_size) + { + unsigned HOST_WIDE_INT rtsd_size; + + /* See if we can use the RTSD instruction. */ + rtsd_size = total_size + regs_size; + if (rtsd_size < 1024 && (rtsd_size % 4) == 0) + { + if (low) + emit_jump_insn (gen_pop_and_return + (GEN_INT (rtsd_size), + gen_rx_rtsd_vector (rtsd_size, low, high))); + else + emit_jump_insn (gen_deallocate_and_return (GEN_INT (total_size))); + + return; + } + + emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, + GEN_INT (total_size))); + } + + if (low) + emit_jump_insn (gen_pop_and_return (GEN_INT (regs_size), + gen_rx_rtsd_vector (regs_size, + low, high))); + else + emit_jump_insn (gen_simple_return ()); +} + + +/* Compute the offset (in words) between FROM (arg pointer + or frame pointer) and TO (frame pointer or stack pointer). + See ASCII art comment at the start of rx_expand_prologue + for more information. */ + +int +rx_initial_elimination_offset (int from, int to) +{ + unsigned int low; + unsigned int high; + unsigned int frame_size; + unsigned int stack_size; + unsigned int mask; + + rx_get_stack_layout (& low, & high, & mask, & frame_size, & stack_size); + + if (from == ARG_POINTER_REGNUM) + { + /* Extend the computed size of the stack frame to + include the registers pushed in the prologue. */ + if (low) + frame_size += ((high - low) + 1) * UNITS_PER_WORD; + else + frame_size += bit_count (mask) * UNITS_PER_WORD; + + /* Remember to include the return address. */ + frame_size += 1 * UNITS_PER_WORD; + + if (to == FRAME_POINTER_REGNUM) + return frame_size; + + gcc_assert (to == STACK_POINTER_REGNUM); + return frame_size + stack_size; + } + + gcc_assert (from == FRAME_POINTER_REGNUM && to == STACK_POINTER_REGNUM); + return stack_size; +} + +/* Update the status of the condition + codes (cc0) based on the given INSN. */ + +void +rx_notice_update_cc (rtx body, rtx insn) +{ + switch (get_attr_cc (insn)) + { + case CC_NONE: + /* Insn does not affect cc0 at all. */ + break; + case CC_CLOBBER: + /* Insn doesn't leave cc0 in a usable state. */ + CC_STATUS_INIT; + break; + case CC_SET_ZSOC: + /* The insn sets all the condition code bits. */ + CC_STATUS_INIT; + cc_status.value1 = SET_SRC (body); + break; + case CC_SET_ZSO: + /* Insn sets the Z,S and O flags, but not the C flag. */ + CC_STATUS_INIT; + cc_status.flags |= CC_NO_CARRY; + /* Do not set the value1 field in this case. The final_scan_insn() + function naively believes that if cc_status.value1 is set then + it can eliminate *any* comparison against that value, even if + the type of comparison cannot be satisfied by the range of flag + bits being set here. See gcc.c-torture/execute/20041210-1.c + for an example of this in action. */ + break; + case CC_SET_ZS: + /* Insn sets the Z and S flags, but not the O or C flags. */ + CC_STATUS_INIT; + cc_status.flags |= (CC_NO_CARRY | CC_NO_OVERFLOW); + /* See comment above regarding cc_status.value1. */ + break; + default: + gcc_unreachable (); + } +} + +/* Decide if a variable should go into one of the small data sections. */ + +static bool +rx_in_small_data (const_tree decl) +{ + int size; + const_tree section; + + if (rx_small_data_limit == 0) + return false; + + if (TREE_CODE (decl) != VAR_DECL) + return false; + + /* We do not put read-only variables into a small data area because + they would be placed with the other read-only sections, far away + from the read-write data sections, and we only have one small + data area pointer. + Similarly commons are placed in the .bss section which might be + far away (and out of alignment with respect to) the .data section. */ + if (TREE_READONLY (decl) || DECL_COMMON (decl)) + return false; + + section = DECL_SECTION_NAME (decl); + if (section) + { + const char * const name = TREE_STRING_POINTER (section); + + return (strcmp (name, "D_2") == 0) || (strcmp (name, "B_2") == 0); + } + + size = int_size_in_bytes (TREE_TYPE (decl)); + + return (size > 0) && (size <= rx_small_data_limit); +} + +/* Return a section for X. + The only special thing we do here is to honor small data. */ + +static section * +rx_select_rtx_section (enum machine_mode mode, + rtx x, + unsigned HOST_WIDE_INT align) +{ + if (rx_small_data_limit > 0 + && GET_MODE_SIZE (mode) <= rx_small_data_limit + && align <= (unsigned HOST_WIDE_INT) rx_small_data_limit * BITS_PER_UNIT) + return sdata_section; + + return default_elf_select_rtx_section (mode, x, align); +} + +static section * +rx_select_section (tree decl, + int reloc, + unsigned HOST_WIDE_INT align) +{ + if (rx_small_data_limit > 0) + { + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_SDATA: return sdata_section; + case SECCAT_SBSS: return sbss_section; + case SECCAT_SRODATA: + /* Fall through. We do not put small, read only + data into the C_2 section because we are not + using the C_2 section. We do not use the C_2 + section because it is located with the other + read-only data sections, far away from the read-write + data sections and we only have one small data + pointer (r13). */ + default: + break; + } + } + + /* If we are supporting the Renesas assembler + we cannot use mergeable sections. */ + if (TARGET_AS100_SYNTAX) + switch (categorize_decl_for_section (decl, reloc)) + { + case SECCAT_RODATA_MERGE_CONST: + case SECCAT_RODATA_MERGE_STR_INIT: + case SECCAT_RODATA_MERGE_STR: + return readonly_data_section; + + default: + break; + } + + return default_elf_select_section (decl, reloc, align); +} + +enum rx_builtin +{ + RX_BUILTIN_BRK, + RX_BUILTIN_CLRPSW, + RX_BUILTIN_INT, + RX_BUILTIN_MACHI, + RX_BUILTIN_MACLO, + RX_BUILTIN_MULHI, + RX_BUILTIN_MULLO, + RX_BUILTIN_MVFACHI, + RX_BUILTIN_MVFACMI, + RX_BUILTIN_MVFC, + RX_BUILTIN_MVTACHI, + RX_BUILTIN_MVTACLO, + RX_BUILTIN_MVTC, + RX_BUILTIN_MVTIPL, + RX_BUILTIN_RACW, + RX_BUILTIN_REVW, + RX_BUILTIN_RMPA, + RX_BUILTIN_ROUND, + RX_BUILTIN_SAT, + RX_BUILTIN_SETPSW, + RX_BUILTIN_WAIT, + RX_BUILTIN_max +}; + +static void +rx_init_builtins (void) +{ +#define ADD_RX_BUILTIN1(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE##_type_node, \ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_RX_BUILTIN2(UC_NAME, LC_NAME, RET_TYPE, ARG_TYPE1, ARG_TYPE2) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + +#define ADD_RX_BUILTIN3(UC_NAME,LC_NAME,RET_TYPE,ARG_TYPE1,ARG_TYPE2,ARG_TYPE3) \ + add_builtin_function ("__builtin_rx_" LC_NAME, \ + build_function_type_list (RET_TYPE##_type_node, \ + ARG_TYPE1##_type_node,\ + ARG_TYPE2##_type_node,\ + ARG_TYPE3##_type_node,\ + NULL_TREE), \ + RX_BUILTIN_##UC_NAME, \ + BUILT_IN_MD, NULL, NULL_TREE) + + ADD_RX_BUILTIN1 (BRK, "brk", void, void); + ADD_RX_BUILTIN1 (CLRPSW, "clrpsw", void, integer); + ADD_RX_BUILTIN1 (SETPSW, "setpsw", void, integer); + ADD_RX_BUILTIN1 (INT, "int", void, integer); + ADD_RX_BUILTIN2 (MACHI, "machi", void, intSI, intSI); + ADD_RX_BUILTIN2 (MACLO, "maclo", void, intSI, intSI); + ADD_RX_BUILTIN2 (MULHI, "mulhi", void, intSI, intSI); + ADD_RX_BUILTIN2 (MULLO, "mullo", void, intSI, intSI); + ADD_RX_BUILTIN1 (MVFACHI, "mvfachi", intSI, void); + ADD_RX_BUILTIN1 (MVFACMI, "mvfacmi", intSI, void); + ADD_RX_BUILTIN1 (MVTACHI, "mvtachi", void, intSI); + ADD_RX_BUILTIN1 (MVTACLO, "mvtaclo", void, intSI); + ADD_RX_BUILTIN1 (RMPA, "rmpa", void, void); + ADD_RX_BUILTIN1 (MVFC, "mvfc", intSI, integer); + ADD_RX_BUILTIN2 (MVTC, "mvtc", void, integer, integer); + ADD_RX_BUILTIN1 (MVTIPL, "mvtipl", void, integer); + ADD_RX_BUILTIN1 (RACW, "racw", void, integer); + ADD_RX_BUILTIN1 (ROUND, "round", intSI, float); + ADD_RX_BUILTIN1 (REVW, "revw", intSI, intSI); + ADD_RX_BUILTIN1 (SAT, "sat", intSI, intSI); + ADD_RX_BUILTIN1 (WAIT, "wait", void, void); +} + +static rtx +rx_expand_void_builtin_1_arg (rtx arg, rtx (* gen_func)(rtx), bool reg) +{ + if (reg && ! REG_P (arg)) + arg = force_reg (SImode, arg); + + emit_insn (gen_func (arg)); + + return NULL_RTX; +} + +static rtx +rx_expand_builtin_mvtc (tree exp) +{ + rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); + + if (! CONST_INT_P (arg1)) + return NULL_RTX; + + if (! REG_P (arg2)) + arg2 = force_reg (SImode, arg2); + + emit_insn (gen_mvtc (arg1, arg2)); + + return NULL_RTX; +} + +static rtx +rx_expand_builtin_mvfc (tree t_arg, rtx target) +{ + rtx arg = expand_normal (t_arg); + + if (! CONST_INT_P (arg)) + return NULL_RTX; + + if (! REG_P (target)) + target = force_reg (SImode, target); + + emit_insn (gen_mvfc (target, arg)); + + return target; +} + +static rtx +rx_expand_builtin_mvtipl (rtx arg) +{ + /* The RX610 does not support the MVTIPL instruction. */ + if (rx_cpu_type == RX610) + return NULL_RTX; + + if (! CONST_INT_P (arg) || ! IN_RANGE (arg, 0, (1 << 4) - 1)) + return NULL_RTX; + + emit_insn (gen_mvtipl (arg)); + + return NULL_RTX; +} + +static rtx +rx_expand_builtin_mac (tree exp, rtx (* gen_func)(rtx, rtx)) +{ + rtx arg1 = expand_normal (CALL_EXPR_ARG (exp, 0)); + rtx arg2 = expand_normal (CALL_EXPR_ARG (exp, 1)); + + if (! REG_P (arg1)) + arg1 = force_reg (SImode, arg1); + + if (! REG_P (arg2)) + arg2 = force_reg (SImode, arg2); + + emit_insn (gen_func (arg1, arg2)); + + return NULL_RTX; +} + +static rtx +rx_expand_int_builtin_1_arg (rtx arg, + rtx target, + rtx (* gen_func)(rtx, rtx), + bool mem_ok) +{ + if (! REG_P (arg)) + if (!mem_ok || ! MEM_P (arg)) + arg = force_reg (SImode, arg); + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target, arg)); + + return target; +} + +static rtx +rx_expand_int_builtin_0_arg (rtx target, rtx (* gen_func)(rtx)) +{ + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_func (target)); + + return target; +} + +static rtx +rx_expand_builtin_round (rtx arg, rtx target) +{ + if ((! REG_P (arg) && ! MEM_P (arg)) + || GET_MODE (arg) != SFmode) + arg = force_reg (SFmode, arg); + + if (target == NULL_RTX || ! REG_P (target)) + target = gen_reg_rtx (SImode); + + emit_insn (gen_lrintsf2 (target, arg)); + + return target; +} + +static rtx +rx_expand_builtin (tree exp, + rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + enum machine_mode mode ATTRIBUTE_UNUSED, + int ignore ATTRIBUTE_UNUSED) +{ + tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); + tree arg = CALL_EXPR_ARGS (exp) ? CALL_EXPR_ARG (exp, 0) : NULL_TREE; + rtx op = arg ? expand_normal (arg) : NULL_RTX; + unsigned int fcode = DECL_FUNCTION_CODE (fndecl); + + switch (fcode) + { + case RX_BUILTIN_BRK: emit_insn (gen_brk ()); return NULL_RTX; + case RX_BUILTIN_CLRPSW: return rx_expand_void_builtin_1_arg + (op, gen_clrpsw, false); + case RX_BUILTIN_SETPSW: return rx_expand_void_builtin_1_arg + (op, gen_setpsw, false); + case RX_BUILTIN_INT: return rx_expand_void_builtin_1_arg + (op, gen_int, false); + case RX_BUILTIN_MACHI: return rx_expand_builtin_mac (exp, gen_machi); + case RX_BUILTIN_MACLO: return rx_expand_builtin_mac (exp, gen_maclo); + case RX_BUILTIN_MULHI: return rx_expand_builtin_mac (exp, gen_mulhi); + case RX_BUILTIN_MULLO: return rx_expand_builtin_mac (exp, gen_mullo); + case RX_BUILTIN_MVFACHI: return rx_expand_int_builtin_0_arg + (target, gen_mvfachi); + case RX_BUILTIN_MVFACMI: return rx_expand_int_builtin_0_arg + (target, gen_mvfacmi); + case RX_BUILTIN_MVTACHI: return rx_expand_void_builtin_1_arg + (op, gen_mvtachi, true); + case RX_BUILTIN_MVTACLO: return rx_expand_void_builtin_1_arg + (op, gen_mvtaclo, true); + case RX_BUILTIN_RMPA: emit_insn (gen_rmpa ()); return NULL_RTX; + case RX_BUILTIN_MVFC: return rx_expand_builtin_mvfc (arg, target); + case RX_BUILTIN_MVTC: return rx_expand_builtin_mvtc (exp); + case RX_BUILTIN_MVTIPL: return rx_expand_builtin_mvtipl (op); + case RX_BUILTIN_RACW: return rx_expand_void_builtin_1_arg + (op, gen_racw, false); + case RX_BUILTIN_ROUND: return rx_expand_builtin_round (op, target); + case RX_BUILTIN_REVW: return rx_expand_int_builtin_1_arg + (op, target, gen_revw, false); + case RX_BUILTIN_SAT: return rx_expand_int_builtin_1_arg + (op, target, gen_sat, false); + case RX_BUILTIN_WAIT: emit_insn (gen_wait ()); return NULL_RTX; + + default: + internal_error ("bad builtin code"); + break; + } + + return NULL_RTX; +} + +/* Place an element into a constructor or destructor section. + Like default_ctor_section_asm_out_constructor in varasm.c + except that it uses .init_array (or .fini_array) and it + handles constructor priorities. */ + +static void +rx_elf_asm_cdtor (rtx symbol, int priority, bool is_ctor) +{ + section * s; + + if (priority != DEFAULT_INIT_PRIORITY) + { + char buf[18]; + + sprintf (buf, "%s.%.5u", + is_ctor ? ".init_array" : ".fini_array", + priority); + s = get_section (buf, SECTION_WRITE, NULL_TREE); + } + else if (is_ctor) + s = ctors_section; + else + s = dtors_section; + + switch_to_section (s); + assemble_align (POINTER_SIZE); + assemble_integer (symbol, POINTER_SIZE / BITS_PER_UNIT, POINTER_SIZE, 1); +} + +static void +rx_elf_asm_constructor (rtx symbol, int priority) +{ + rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */true); +} + +static void +rx_elf_asm_destructor (rtx symbol, int priority) +{ + rx_elf_asm_cdtor (symbol, priority, /* is_ctor= */false); +} + +/* Check "fast_interrupt", "interrupt" and "naked" attributes. */ + +static tree +rx_handle_func_attribute (tree * node, + tree name, + tree args, + int flags ATTRIBUTE_UNUSED, + bool * no_add_attrs) +{ + gcc_assert (DECL_P (* node)); + gcc_assert (args == NULL_TREE); + + if (TREE_CODE (* node) != FUNCTION_DECL) + { + warning (OPT_Wattributes, "%qE attribute only applies to functions", + name); + * no_add_attrs = true; + } + + /* FIXME: We ought to check for conflicting attributes. */ + + /* FIXME: We ought to check that the interrupt and exception + handler attributes have been applied to void functions. */ + return NULL_TREE; +} + +/* Table of RX specific attributes. */ +const struct attribute_spec rx_attribute_table[] = +{ + /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler. */ + { "fast_interrupt", 0, 0, true, false, false, rx_handle_func_attribute }, + { "interrupt", 0, 0, true, false, false, rx_handle_func_attribute }, + { "naked", 0, 0, true, false, false, rx_handle_func_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +static bool +rx_allocate_stack_slots_for_args (void) +{ + /* Naked functions should not allocate stack slots for arguments. */ + return ! is_naked_func (NULL_TREE); +} + +static bool +rx_func_attr_inlinable (const_tree decl) +{ + return ! is_fast_interrupt_func (decl) + && ! is_interrupt_func (decl) + && ! is_naked_func (decl); +} + +static void +rx_file_start (void) +{ + if (! TARGET_AS100_SYNTAX) + default_file_start (); +} + +static bool +rx_is_ms_bitfield_layout (const_tree record_type ATTRIBUTE_UNUSED) +{ + return TRUE; +} + +/* Try to generate code for the "isnv" pattern which inserts bits + into a word. + operands[0] => Location to be altered. + operands[1] => Number of bits to change. + operands[2] => Starting bit. + operands[3] => Value to insert. + Returns TRUE if successful, FALSE otherwise. */ + +bool +rx_expand_insv (rtx * operands) +{ + if (INTVAL (operands[1]) != 1 + || ! CONST_INT_P (operands[3])) + return false; + + if (MEM_P (operands[0]) + && INTVAL (operands[2]) > 7) + return false; + + switch (INTVAL (operands[3])) + { + case 0: + if (MEM_P (operands[0])) + emit_insn (gen_bitclr_in_memory (operands[0], operands[0], + operands[2])); + else + emit_insn (gen_bitclr (operands[0], operands[0], operands[2])); + break; + case 1: + case -1: + if (MEM_P (operands[0])) + emit_insn (gen_bitset_in_memory (operands[0], operands[0], + operands[2])); + else + emit_insn (gen_bitset (operands[0], operands[0], operands[2])); + break; + default: + return false; + } + return true; +} + +/* Returns true if X a legitimate constant for an immediate + operand on the RX. X is already known to satisfy CONSTANT_P. */ + +bool +rx_is_legitimate_constant (rtx x) +{ + HOST_WIDE_INT val; + + switch (GET_CODE (x)) + { + case CONST: + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS) + { + if (! CONST_INT_P (XEXP (x, 1))) + return false; + + /* GCC would not pass us CONST_INT + CONST_INT so we + know that we have {SYMBOL|LABEL} + CONST_INT. */ + x = XEXP (x, 0); + gcc_assert (! CONST_INT_P (x)); + } + + switch (GET_CODE (x)) + { + case LABEL_REF: + case SYMBOL_REF: + return true; + + /* One day we may have to handle UNSPEC constants here. */ + default: + /* FIXME: Can this ever happen ? */ + abort (); + return false; + } + break; + + case LABEL_REF: + case SYMBOL_REF: + return true; + case CONST_DOUBLE: + return rx_max_constant_size == 0; + case CONST_VECTOR: + return false; + default: + gcc_assert (CONST_INT_P (x)); + break; + } + + if (rx_max_constant_size == 0) + /* If there is no constraint on the size of constants + used as operands, then any value is legitimate. */ + return true; + + val = INTVAL (x); + + /* rx_max_constant_size specifies the maximum number + of bytes that can be used to hold a signed value. */ + return IN_RANGE (val, (-1 << (rx_max_constant_size * 8)), + ( 1 << (rx_max_constant_size * 8))); +} + +/* This is a tri-state variable. The default value of 0 means that the user + has specified neither -mfpu nor -mnofpu on the command line. In this case + the selection of RX FPU instructions is entirely based upon the size of + the floating point object and whether unsafe math optimizations were + enabled. If 32-bit doubles have been enabled then both floats and doubles + can make use of FPU instructions, otherwise only floats may do so. + + If the value is 1 then the user has specified -mfpu and the FPU + instructions should be used. Unsafe math optimizations will automatically + be enabled and doubles set to 32-bits. If the value is -1 then -mnofpu + has been specified and FPU instructions will not be used, even if unsafe + math optimizations have been enabled. */ +int rx_enable_fpu = 0; + +/* Extra processing for target specific command line options. */ + +static bool +rx_handle_option (size_t code, const char * arg ATTRIBUTE_UNUSED, int value) +{ + switch (code) + { + /* -mfpu enables the use of RX FPU instructions. This implies the use + of 32-bit doubles and also the enabling of fast math optimizations. + (Since the RX FPU instructions are not IEEE compliant). The -mnofpu + option disables the use of RX FPU instructions, but does not make + place any constraints on the size of doubles or the use of fast math + optimizations. + + The selection of 32-bit vs 64-bit doubles is handled by the setting + of the 32BIT_DOUBLES mask in the rx.opt file. Enabling fast math + optimizations is performed in OVERRIDE_OPTIONS since if it was done + here it could be overridden by a -fno-fast-math option specified + *earlier* on the command line. (Target specific options are + processed before generic ones). */ + case OPT_fpu: + rx_enable_fpu = 1; + break; + + case OPT_nofpu: + rx_enable_fpu = -1; + break; + + case OPT_mint_register_: + switch (value) + { + case 4: + fixed_regs[10] = call_used_regs [10] = 1; + /* Fall through. */ + case 3: + fixed_regs[11] = call_used_regs [11] = 1; + /* Fall through. */ + case 2: + fixed_regs[12] = call_used_regs [12] = 1; + /* Fall through. */ + case 1: + fixed_regs[13] = call_used_regs [13] = 1; + /* Fall through. */ + case 0: + return true; + default: + return false; + } + break; + + case OPT_mmax_constant_size_: + /* Make sure that the -mmax-constant_size option is in range. */ + return IN_RANGE (value, 0, 4); + + case OPT_mcpu_: + case OPT_patch_: + if (strcasecmp (arg, "RX610") == 0) + rx_cpu_type = RX610; + /* FIXME: Should we check for non-RX cpu names here ? */ + break; + + default: + break; + } + + return true; +} + +static int +rx_address_cost (rtx addr, bool speed) +{ + rtx a, b; + + if (GET_CODE (addr) != PLUS) + return COSTS_N_INSNS (1); + + a = XEXP (addr, 0); + b = XEXP (addr, 1); + + if (REG_P (a) && REG_P (b)) + /* Try to discourage REG+REG addressing as it keeps two registers live. */ + return COSTS_N_INSNS (4); + + if (speed) + /* [REG+OFF] is just as fast as [REG]. */ + return COSTS_N_INSNS (1); + + if (CONST_INT_P (b) + && ((INTVAL (b) > 128) || INTVAL (b) < -127)) + /* Try to discourage REG + when optimizing for size. */ + return COSTS_N_INSNS (2); + + return COSTS_N_INSNS (1); +} + +static bool +rx_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to) +{ + /* We can always eliminate to the frame pointer. + We can eliminate to the stack pointer unless a frame + pointer is needed. */ + + return to == FRAME_POINTER_REGNUM + || ( to == STACK_POINTER_REGNUM && ! frame_pointer_needed); +} + + +static void +rx_trampoline_template (FILE * file) +{ + /* Output assembler code for a block containing the constant + part of a trampoline, leaving space for the variable parts. + + On the RX, (where r8 is the static chain regnum) the trampoline + looks like: + + mov #, r8 + mov #, r9 + jmp r9 + + In big-endian-data-mode however instructions are read into the CPU + 4 bytes at a time. These bytes are then swapped around before being + passed to the decoder. So...we must partition our trampoline into + 4 byte packets and swap these packets around so that the instruction + reader will reverse the process. But, in order to avoid splitting + the 32-bit constants across these packet boundaries, (making inserting + them into the constructed trampoline very difficult) we have to pad the + instruction sequence with NOP insns. ie: + + nop + nop + mov.l #<...>, r8 + nop + nop + mov.l #<...>, r9 + jmp r9 + nop + nop */ + + if (! TARGET_BIG_ENDIAN_DATA) + { + asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", STATIC_CHAIN_REGNUM); + asm_fprintf (file, "\tmov.L\t#0deadbeefH, r%d\n", TRAMPOLINE_TEMP_REGNUM); + asm_fprintf (file, "\tjmp\tr%d\n", TRAMPOLINE_TEMP_REGNUM); + } + else + { + char r8 = '0' + STATIC_CHAIN_REGNUM; + char r9 = '0' + TRAMPOLINE_TEMP_REGNUM; + + if (TARGET_AS100_SYNTAX) + { + asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r8); + asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n"); + asm_fprintf (file, "\t.BYTE 0%c2H, 0fbH, 003H, 003H\n", r9); + asm_fprintf (file, "\t.BYTE 0deH, 0adH, 0beH, 0efH\n"); + asm_fprintf (file, "\t.BYTE 003H, 003H, 00%cH, 07fH\n", r9); + } + else + { + asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r8); + asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n"); + asm_fprintf (file, "\t.byte 0x%c2, 0xfb, 0x03, 0x03\n", r9); + asm_fprintf (file, "\t.byte 0xde, 0xad, 0xbe, 0xef\n"); + asm_fprintf (file, "\t.byte 0x03, 0x03, 0x0%c, 0x7f\n", r9); + } + } +} + +static void +rx_trampoline_init (rtx tramp, tree fndecl, rtx chain) +{ + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); + + emit_block_move (tramp, assemble_trampoline_template (), + GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL); + + if (TARGET_BIG_ENDIAN_DATA) + { + emit_move_insn (adjust_address (tramp, SImode, 4), chain); + emit_move_insn (adjust_address (tramp, SImode, 12), fnaddr); + } + else + { + emit_move_insn (adjust_address (tramp, SImode, 2), chain); + emit_move_insn (adjust_address (tramp, SImode, 6 + 2), fnaddr); + } +} + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE rx_function_value + +#undef TARGET_RETURN_IN_MSB +#define TARGET_RETURN_IN_MSB rx_return_in_msb + +#undef TARGET_IN_SMALL_DATA_P +#define TARGET_IN_SMALL_DATA_P rx_in_small_data + +#undef TARGET_RETURN_IN_MEMORY +#define TARGET_RETURN_IN_MEMORY rx_return_in_memory + +#undef TARGET_HAVE_SRODATA_SECTION +#define TARGET_HAVE_SRODATA_SECTION true + +#undef TARGET_ASM_SELECT_RTX_SECTION +#define TARGET_ASM_SELECT_RTX_SECTION rx_select_rtx_section + +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION rx_select_section + +#undef TARGET_INIT_BUILTINS +#define TARGET_INIT_BUILTINS rx_init_builtins + +#undef TARGET_EXPAND_BUILTIN +#define TARGET_EXPAND_BUILTIN rx_expand_builtin + +#undef TARGET_ASM_CONSTRUCTOR +#define TARGET_ASM_CONSTRUCTOR rx_elf_asm_constructor + +#undef TARGET_ASM_DESTRUCTOR +#define TARGET_ASM_DESTRUCTOR rx_elf_asm_destructor + +#undef TARGET_STRUCT_VALUE_RTX +#define TARGET_STRUCT_VALUE_RTX rx_struct_value_rtx + +#undef TARGET_ATTRIBUTE_TABLE +#define TARGET_ATTRIBUTE_TABLE rx_attribute_table + +#undef TARGET_ASM_FILE_START +#define TARGET_ASM_FILE_START rx_file_start + +#undef TARGET_MS_BITFIELD_LAYOUT_P +#define TARGET_MS_BITFIELD_LAYOUT_P rx_is_ms_bitfield_layout + +#undef TARGET_LEGITIMATE_ADDRESS_P +#define TARGET_LEGITIMATE_ADDRESS_P rx_is_legitimate_address + +#undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS +#define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS rx_allocate_stack_slots_for_args + +#undef TARGET_ASM_FUNCTION_PROLOGUE +#define TARGET_ASM_FUNCTION_PROLOGUE rx_output_function_prologue + +#undef TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P +#define TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P rx_func_attr_inlinable + +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION rx_set_current_function + +#undef TARGET_HANDLE_OPTION +#define TARGET_HANDLE_OPTION rx_handle_option + +#undef TARGET_ASM_INTEGER +#define TARGET_ASM_INTEGER rx_assemble_integer + +#undef TARGET_USE_BLOCKS_FOR_CONSTANT_P +#define TARGET_USE_BLOCKS_FOR_CONSTANT_P hook_bool_mode_const_rtx_true + +#undef TARGET_MAX_ANCHOR_OFFSET +#define TARGET_MAX_ANCHOR_OFFSET 32 + +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST rx_address_cost + +#undef TARGET_CAN_ELIMINATE +#define TARGET_CAN_ELIMINATE rx_can_eliminate + +#undef TARGET_ASM_TRAMPOLINE_TEMPLATE +#define TARGET_ASM_TRAMPOLINE_TEMPLATE rx_trampoline_template + +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT rx_trampoline_init + +struct gcc_target targetm = TARGET_INITIALIZER; + +/* #include "gt-rx.h" */ diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h new file mode 100644 index 00000000000..bb7cf7f1e3e --- /dev/null +++ b/gcc/config/rx/rx.h @@ -0,0 +1,659 @@ +/* GCC backend definitions for the Renesas RX processor. + Copyright (C) 2008, 2009 Free Software Foundation, Inc. + Contributed by Red Hat. + + 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 3, 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 COPYING3. If not see + . */ + + +#define TARGET_CPU_CPP_BUILTINS() \ + do \ + { \ + builtin_define ("__RX__"); \ + builtin_assert ("cpu=RX"); \ + if (rx_cpu_type == RX610) \ + builtin_assert ("machine=RX610"); \ + else \ + builtin_assert ("machine=RX600"); \ + \ + if (TARGET_BIG_ENDIAN_DATA) \ + builtin_define ("__RX_BIG_ENDIAN__"); \ + else \ + builtin_define ("__RX_LITTLE_ENDIAN__");\ + \ + if (TARGET_32BIT_DOUBLES) \ + builtin_define ("__RX_32BIT_DOUBLES__");\ + else \ + builtin_define ("__RX_64BIT_DOUBLES__");\ + \ + if (ALLOW_RX_FPU_INSNS) \ + builtin_define ("__RX_FPU_INSNS__"); \ + \ + if (TARGET_AS100_SYNTAX) \ + builtin_define ("__RX_AS100_SYNTAX__"); \ + else \ + builtin_define ("__RX_GAS_SYNTAX__"); \ + } \ + while (0) + +enum rx_cpu_types +{ + RX600, + RX610 +}; + +extern enum rx_cpu_types rx_cpu_type; + +#undef CC1_SPEC +#define CC1_SPEC "%{mas100-syntax:%{gdwarf*:%e-mas100-syntax is incompatible with -gdwarf}}" + +#undef STARTFILE_SPEC +#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:crt0.o%s} crtbegin.o%s" + +#undef ENDFILE_SPEC +#define ENDFILE_SPEC "crtend.o%s crtn.o%s" + +#undef ASM_SPEC +#define ASM_SPEC "\ +%{mbig-endian-data:-mbig-endian-data} \ +%{m32bit-doubles:-m32bit-doubles} \ +%{!m32bit-doubles:-m64bit-doubles} \ +%{msmall-data-limit*:-msmall-data-limit} \ +%{mrelax:-relax} \ +" + +#undef LIB_SPEC +#define LIB_SPEC " \ +--start-group \ +-lc \ +%{msim*:-lsim}%{!msim*:-lnosys} \ +%{fprofile-arcs|fprofile-generate|coverage:-lgcov} \ +--end-group \ +%{!T*: %{msim*:%Trx-sim.ld}%{!msim*:%Trx.ld}} \ +" + +#undef LINK_SPEC +#define LINK_SPEC "%{mbig-endian-data:--oformat elf32-rx-be} %{mrelax:-relax}" + + +#define BITS_BIG_ENDIAN 0 +#define BYTES_BIG_ENDIAN TARGET_BIG_ENDIAN_DATA +#define WORDS_BIG_ENDIAN TARGET_BIG_ENDIAN_DATA + +#ifdef __RX_BIG_ENDIAN__ +#define LIBGCC2_WORDS_BIG_ENDIAN 1 +#else +#define LIBGCC2_WORDS_BIG_ENDIAN 0 +#endif + +#define UNITS_PER_WORD 4 + +#define INT_TYPE_SIZE 32 +#define LONG_TYPE_SIZE 32 +#define LONG_LONG_TYPE_SIZE 64 + +#define FLOAT_TYPE_SIZE 32 +#define DOUBLE_TYPE_SIZE (TARGET_32BIT_DOUBLES ? 32 : 64) +#define LONG_DOUBLE_TYPE_SIZE DOUBLE_TYPE_SIZE + +#ifdef __RX_32BIT_DOUBLES__ +#define LIBGCC2_HAS_DF_MODE 0 +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 32 +#define LIBGCC2_DOUBLE_TYPE_SIZE 32 +#else +#define LIBGCC2_HAS_DF_MODE 1 +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE 64 +#define LIBGCC2_DOUBLE_TYPE_SIZE 64 +#endif + +#define DEFAULT_SIGNED_CHAR 0 + +#define STRICT_ALIGNMENT 1 +#define FUNCTION_BOUNDARY 8 +#define BIGGEST_ALIGNMENT 32 +#define STACK_BOUNDARY 32 +#define PARM_BOUNDARY 8 + +#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) 32 + +#define STACK_GROWS_DOWNWARD 1 +#define FRAME_GROWS_DOWNWARD 0 +#define FIRST_PARM_OFFSET(FNDECL) 0 + +#define MAX_REGS_PER_ADDRESS 2 + +#define Pmode SImode +#define POINTER_SIZE 32 +#undef SIZE_TYPE +#define SIZE_TYPE "long unsigned int" +#define POINTERS_EXTEND_UNSIGNED 1 +#define FUNCTION_MODE QImode +#define CASE_VECTOR_MODE Pmode +#define WORD_REGISTER_OPERATIONS 1 +#define HAS_LONG_COND_BRANCH 0 +#define HAS_LONG_UNCOND_BRANCH 0 + +#define MOVE_MAX 4 +#define STARTING_FRAME_OFFSET 0 + +#define RETURN_POPS_ARGS(FUNDECL, FUNTYPE, SIZE) 0 +#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1 + +#define LEGITIMATE_CONSTANT_P(X) rx_is_legitimate_constant (X) + +#define HANDLE_PRAGMA_PACK_PUSH_POP 1 + +#define HAVE_PRE_DECCREMENT 1 +#define HAVE_POST_INCREMENT 1 + +#define MOVE_RATIO(SPEED) ((SPEED) ? 4 : 2) +#define SLOW_BYTE_ACCESS 1 + +#define STORE_FLAG_VALUE 1 +#define LOAD_EXTEND_OP(MODE) SIGN_EXTEND +#define SHORT_IMMEDIATES_SIGN_EXTEND 1 + +enum reg_class +{ + NO_REGS, /* No registers in set. */ + GR_REGS, /* Integer registers. */ + ALL_REGS, /* All registers. */ + LIM_REG_CLASSES /* Max value + 1. */ +}; + +#define REG_CLASS_NAMES \ +{ \ + "NO_REGS", \ + "GR_REGS", \ + "ALL_REGS" \ +} + +#define REG_CLASS_CONTENTS \ +{ \ + { 0x00000000 }, /* No registers, */ \ + { 0x0000ffff }, /* Integer registers. */ \ + { 0x0000ffff } /* All registers. */ \ +} + +#define IRA_COVER_CLASSES \ + { \ + GR_REGS, LIM_REG_CLASSES \ + } + +#define SMALL_REGISTER_CLASSES 0 +#define N_REG_CLASSES (int) LIM_REG_CLASSES +#define CLASS_MAX_NREGS(CLASS, MODE) ((GET_MODE_SIZE (MODE) \ + + UNITS_PER_WORD - 1) \ + / UNITS_PER_WORD) + +#define GENERAL_REGS GR_REGS +#define BASE_REG_CLASS GR_REGS +#define INDEX_REG_CLASS GR_REGS + +#define FIRST_PSEUDO_REGISTER 16 + +#define REGNO_REG_CLASS(REGNO) ((REGNO) < FIRST_PSEUDO_REGISTER \ + ? GR_REGS : NO_REGS) + +#define STACK_POINTER_REGNUM 0 +#define FUNC_RETURN_REGNUM 1 +#define FRAME_POINTER_REGNUM 6 +#define ARG_POINTER_REGNUM 7 +#define STATIC_CHAIN_REGNUM 8 +#define TRAMPOLINE_TEMP_REGNUM 9 +#define STRUCT_VAL_REGNUM 15 + +/* This is the register which is used to hold the address of the start + of the small data area, if that feature is being used. Note - this + register must not be call_used because otherwise library functions + that are compiled without small data support might clobber it. + + FIXME: The function gcc/config/rx/rx.c:rx_gen_move_template() has a + built in copy of this register's name, rather than constructing the + name from this #define. */ +#define GP_BASE_REGNUM 13 + +#define ELIMINABLE_REGS \ +{{ ARG_POINTER_REGNUM, STACK_POINTER_REGNUM }, \ + { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM }, \ + { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }} + +#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ + (OFFSET) = rx_initial_elimination_offset ((FROM), (TO)) + + +#define FUNCTION_ARG_REGNO_P(N) (((N) >= 1) && ((N) <= 4)) +#define FUNCTION_VALUE_REGNO_P(N) ((N) == FUNC_RETURN_REGNUM) +#define DEFAULT_PCC_STRUCT_RETURN 0 + +#define FIXED_REGISTERS \ +{ \ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 \ +} + +#define CALL_USED_REGISTERS \ +{ \ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 \ +} + +#define CONDITIONAL_REGISTER_USAGE \ + rx_conditional_register_usage () + +#define LIBCALL_VALUE(MODE) \ + gen_rtx_REG (((GET_MODE_CLASS (MODE) != MODE_INT \ + || GET_MODE_SIZE (MODE) >= 4) \ + ? (MODE) \ + : SImode), \ + FUNC_RETURN_REGNUM) + +/* Order of allocation of registers. */ + +#define REG_ALLOC_ORDER \ +{ 7, 10, 11, 12, 13, 14, 4, 3, 2, 1, 9, 8, 6, 5, 15 \ +} + +#define PREFERRED_RELOAD_CLASS(X,CLASS) CLASS + +#define REGNO_IN_RANGE(REGNO, MIN, MAX) \ + (IN_RANGE ((REGNO), (MIN), (MAX)) \ + || (reg_renumber != NULL \ + && reg_renumber[(REGNO)] >= (MIN) \ + && reg_renumber[(REGNO)] <= (MAX))) + +#ifdef REG_OK_STRICT +#define REGNO_OK_FOR_BASE_P(regno) REGNO_IN_RANGE (regno, 0, 15) +#else +#define REGNO_OK_FOR_BASE_P(regno) 1 +#endif + +#define REGNO_OK_FOR_INDEX_P(regno) REGNO_OK_FOR_BASE_P (regno) + +#define RTX_OK_FOR_BASE(X, STRICT) \ + ((STRICT) ? \ + ( (REG_P (X) \ + && REGNO_IN_RANGE (REGNO (X), 0, 15)) \ + || (GET_CODE (X) == SUBREG \ + && REG_P (SUBREG_REG (X)) \ + && REGNO_IN_RANGE (REGNO (SUBREG_REG (X)), 0, 15))) \ + : \ + ( (REG_P (X) \ + || (GET_CODE (X) == SUBREG \ + && REG_P (SUBREG_REG (X)))))) + +#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL) \ + do \ + { \ + if (rx_is_mode_dependent_addr (ADDR)) \ + goto LABEL; \ + } \ + while (0) + + +#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \ + ((COUNT) == 0 \ + ? gen_rtx_MEM (Pmode, gen_rtx_PLUS (Pmode, arg_pointer_rtx, GEN_INT (-4))) \ + : NULL_RTX) + +#define INCOMING_RETURN_ADDR_RTX gen_rtx_MEM (Pmode, stack_pointer_rtx) + +#define ACCUMULATE_OUTGOING_ARGS 1 + +typedef unsigned int CUMULATIVE_ARGS; + +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \ + (CUM) = 0 + +#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \ + rx_function_arg (& CUM, MODE, TYPE, NAMED) + +#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED) \ + (CUM) += rx_function_arg_size (MODE, TYPE) + +#define TRAMPOLINE_SIZE (! TARGET_BIG_ENDIAN_DATA ? 14 : 20) +#define TRAMPOLINE_ALIGNMENT 32 + +#define NO_PROFILE_COUNTERS 1 +#define PROFILE_BEFORE_PROLOGUE 1 + +#define FUNCTION_PROFILER(FILE, LABELNO) \ + fprintf (FILE, "\tbsr\t__mcount\n"); + + +#define HARD_REGNO_NREGS(REGNO, MODE) CLASS_MAX_NREGS (0, MODE) + +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + REGNO_REG_CLASS (REGNO) == GR_REGS + +#define MODES_TIEABLE_P(MODE1, MODE2) \ + ( ( GET_MODE_CLASS (MODE1) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT) \ + == ( GET_MODE_CLASS (MODE2) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT)) + + +#define REGISTER_NAMES \ + { \ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" \ + }; + +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + { "sp", STACK_POINTER_REGNUM } \ + , { "fp", FRAME_POINTER_REGNUM } \ + , { "arg", ARG_POINTER_REGNUM } \ + , { "chain", STATIC_CHAIN_REGNUM } \ +} + +#define DATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION D,DATA" \ + : "\t.section D,\"aw\",@progbits\n\t.p2align 2") + +#define SDATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION D_2,DATA,ALIGN=2" \ + : "\t.section D_2,\"aw\",@progbits\n\t.p2align 1") + +#undef READONLY_DATA_SECTION_ASM_OP +#define READONLY_DATA_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION C,ROMDATA,ALIGN=4" \ + : "\t.section C,\"a\",@progbits\n\t.p2align 2") + +#define BSS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION B,DATA,ALIGN=4" \ + : "\t.section B,\"w\",@nobits\n\t.p2align 2") + +#define SBSS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION B_2,DATA,ALIGN=2" \ + : "\t.section B_2,\"w\",@nobits\n\t.p2align 1") + +/* The following definitions are conditional depending upon whether the + compiler is being built or crtstuff.c is being compiled by the built + compiler. */ +#if defined CRT_BEGIN || defined CRT_END +# ifdef __RX_AS100_SYNTAX +# define TEXT_SECTION_ASM_OP "\t.SECTION P,CODE" +# define CTORS_SECTION_ASM_OP "\t.SECTION init_array,CODE" +# define DTORS_SECTION_ASM_OP "\t.SECTION fini_array,CODE" +# define INIT_ARRAY_SECTION_ASM_OP "\t.SECTION init_array,CODE" +# define FINI_ARRAY_SECTION_ASM_OP "\t.SECTION fini_array,CODE" +# else +# define TEXT_SECTION_ASM_OP "\t.section P,\"ax\"" +# define CTORS_SECTION_ASM_OP \ + "\t.section\t.init_array,\"aw\",@init_array" +# define DTORS_SECTION_ASM_OP \ + "\t.section\t.fini_array,\"aw\",@fini_array" +# define INIT_ARRAY_SECTION_ASM_OP \ + "\t.section\t.init_array,\"aw\",@init_array" +# define FINI_ARRAY_SECTION_ASM_OP \ + "\t.section\t.fini_array,\"aw\",@fini_array" +# endif +#else +# define TEXT_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION P,CODE" : "\t.section P,\"ax\"") + +# define CTORS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION init_array,CODE" \ + : "\t.section\t.init_array,\"aw\",@init_array") + +# define DTORS_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION fini_array,CODE" \ + : "\t.section\t.fini_array,\"aw\",@fini_array") + +# define INIT_ARRAY_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION init_array,CODE" \ + : "\t.section\t.init_array,\"aw\",@init_array") + +# define FINI_ARRAY_SECTION_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.SECTION fini_array,CODE" \ + : "\t.section\t.fini_array,\"aw\",@fini_array") +#endif + +#define GLOBAL_ASM_OP \ + (TARGET_AS100_SYNTAX ? "\t.GLB\t" : "\t.global\t") +#define ASM_COMMENT_START " ;" +#define ASM_APP_ON "" +#define ASM_APP_OFF "" +#define LOCAL_LABEL_PREFIX "L" +#undef USER_LABEL_PREFIX +#define USER_LABEL_PREFIX "_" + +#define ASM_OUTPUT_ALIGN(STREAM, LOG) \ + do \ + { \ + if ((LOG) == 0) \ + break; \ + if (TARGET_AS100_SYNTAX) \ + { \ + if ((LOG) >= 2) \ + fprintf (STREAM, "\t.ALIGN 4\t; %d alignment actually requested\n", 1 << (LOG)); \ + else \ + fprintf (STREAM, "\t.ALIGN 2\n"); \ + } \ + else \ + fprintf (STREAM, "\t.balign %d\n", 1 << (LOG)); \ + } \ + while (0) + +#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \ + fprintf (FILE, TARGET_AS100_SYNTAX ? "\t.LWORD L%d\n" : "\t.long .L%d\n", \ + VALUE) + +/* This is how to output an element of a case-vector that is relative. + Note: The local label referenced by the "3b" below is emitted by + the tablejump insn. */ + +#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \ + fprintf (FILE, TARGET_AS100_SYNTAX \ + ? "\t.LWORD L%d - ?-\n" : "\t.long .L%d - 1b\n", VALUE) + +#define ASM_OUTPUT_SIZE_DIRECTIVE(STREAM, NAME, SIZE) \ + do \ + { \ + HOST_WIDE_INT size_ = (SIZE); \ + \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + \ + fputs (SIZE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fprintf (STREAM, ", " HOST_WIDE_INT_PRINT_DEC "\n", size_); \ + } \ + while (0) + +#define ASM_OUTPUT_MEASURED_SIZE(STREAM, NAME) \ + do \ + { \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + fputs (SIZE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fputs (", .-", STREAM); \ + assemble_name (STREAM, NAME); \ + putc ('\n', STREAM); \ + } \ + while (0) + +#define ASM_OUTPUT_TYPE_DIRECTIVE(STREAM, NAME, TYPE) \ + do \ + { \ + /* The as100 assembler does not have an equivalent of the SVR4 \ + .size pseudo-op. */ \ + if (TARGET_AS100_SYNTAX) \ + break; \ + fputs (TYPE_ASM_OP, STREAM); \ + assemble_name (STREAM, NAME); \ + fputs (", ", STREAM); \ + fprintf (STREAM, TYPE_OPERAND_FMT, TYPE); \ + putc ('\n', STREAM); \ + } \ + while (0) + +#undef ASM_GENERATE_INTERNAL_LABEL +#define ASM_GENERATE_INTERNAL_LABEL(LABEL, PREFIX, NUM) \ + do \ + { \ + sprintf (LABEL, TARGET_AS100_SYNTAX ? "*%s%u" : "*.%s%u", \ + PREFIX, (unsigned) (NUM)); \ + } \ + while (0) + +#undef ASM_OUTPUT_EXTERNAL +#define ASM_OUTPUT_EXTERNAL(FILE, DECL, NAME) \ + do \ + { \ + if (TARGET_AS100_SYNTAX) \ + targetm.asm_out.globalize_label (FILE, NAME); \ + default_elf_asm_output_external (FILE, DECL, NAME); \ + } \ + while (0) + +#undef ASM_OUTPUT_ALIGNED_COMMON +#define ASM_OUTPUT_ALIGNED_COMMON(FILE, NAME, SIZE, ALIGN) \ + do \ + { \ + if (TARGET_AS100_SYNTAX) \ + { \ + fprintf ((FILE), "\t.GLB\t"); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), "\n"); \ + assemble_name ((FILE), (NAME)); \ + switch ((ALIGN) / BITS_PER_UNIT) \ + { \ + case 4: \ + fprintf ((FILE), ":\t.BLKL\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE) / 4); \ + break; \ + case 2: \ + fprintf ((FILE), ":\t.BLKW\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE) / 2); \ + break; \ + default: \ + fprintf ((FILE), ":\t.BLKB\t"HOST_WIDE_INT_PRINT_UNSIGNED"\n",\ + (SIZE)); \ + break; \ + } \ + } \ + else \ + { \ + fprintf ((FILE), "%s", COMMON_ASM_OP); \ + assemble_name ((FILE), (NAME)); \ + fprintf ((FILE), ","HOST_WIDE_INT_PRINT_UNSIGNED",%u\n", \ + (SIZE), (ALIGN) / BITS_PER_UNIT); \ + } \ + } \ + while (0) + +#undef SKIP_ASM_OP +#define SKIP_ASM_OP (TARGET_AS100_SYNTAX ? "\t.BLKB\t" : "\t.zero\t") + +#undef ASM_OUTPUT_LIMITED_STRING +#define ASM_OUTPUT_LIMITED_STRING(FILE, STR) \ + do \ + { \ + const unsigned char *_limited_str = \ + (const unsigned char *) (STR); \ + unsigned ch; \ + \ + fprintf ((FILE), TARGET_AS100_SYNTAX \ + ? "\t.BYTE\t\"" : "\t.string\t\""); \ + \ + for (; (ch = *_limited_str); _limited_str++) \ + { \ + int escape; \ + \ + switch (escape = ESCAPES[ch]) \ + { \ + case 0: \ + putc (ch, (FILE)); \ + break; \ + case 1: \ + fprintf ((FILE), "\\%03o", ch); \ + break; \ + default: \ + putc ('\\', (FILE)); \ + putc (escape, (FILE)); \ + break; \ + } \ + } \ + \ + fprintf ((FILE), TARGET_AS100_SYNTAX ? "\"\n\t.BYTE\t0\n" : "\"\n");\ + } \ + while (0) + +#undef IDENT_ASM_OP +#define IDENT_ASM_OP (TARGET_AS100_SYNTAX \ + ? "\t.END\t; Built by: ": "\t.ident\t") + +/* For PIC put jump tables into the text section so that the offsets that + they contain are always computed between two same-section symbols. */ +#define JUMP_TABLES_IN_TEXT_SECTION (flag_pic) + +#define PRINT_OPERAND(FILE, X, CODE) \ + rx_print_operand (FILE, X, CODE) +#define PRINT_OPERAND_ADDRESS(FILE, ADDR) \ + rx_print_operand_address (FILE, ADDR) + +#define CC_NO_CARRY 0400 +#define NOTICE_UPDATE_CC(EXP, INSN) rx_notice_update_cc (EXP, INSN) + +extern int rx_float_compare_mode; + +/* This is a version of REG_P that also returns TRUE for SUBREGs. */ +#define RX_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG) + +/* Like REG_P except that this macro is true for SET expressions. */ +#define SET_P(rtl) (GET_CODE (rtl) == SET) + +#define CAN_DEBUG_WITHOUT_FP 1 + +/* The AS100 assembler does not support .leb128 and .uleb128, but + the compiler-build-time configure tests will have enabled their + use because GAS supports them. So default to generating STABS + debug information instead of DWARF2 when generating AS100 + compatible output. */ +#undef PREFERRED_DEBUGGING_TYPE +#define PREFERRED_DEBUGGING_TYPE (TARGET_AS100_SYNTAX \ + ? DBX_DEBUG : DWARF2_DEBUG) + +#define INCOMING_FRAME_SP_OFFSET 4 +#define ARG_POINTER_CFA_OFFSET(FNDECL) 4 +#define FRAME_POINTER_CFA_OFFSET(FNDECL) 4 + +extern int rx_enable_fpu; + +/* For some unknown reason LTO compression is not working, at + least on my local system. So set the default compression + level to none, for now. + + For an explanation of rx_flag_no_fpu see rx_handle_option(). */ +#define OVERRIDE_OPTIONS \ + do \ + { \ + if (flag_lto_compression_level == -1) \ + flag_lto_compression_level = 0; \ + \ + if (rx_enable_fpu == 1) \ + set_fast_math_flags (true); \ + } \ + while (0) + +/* This macro is used to decide when RX FPU instructions can be used. */ +#define ALLOW_RX_FPU_INSNS ((rx_enable_fpu != -1) \ + && flag_unsafe_math_optimizations) diff --git a/gcc/config/rx/rx.md b/gcc/config/rx/rx.md new file mode 100644 index 00000000000..360f6235558 --- /dev/null +++ b/gcc/config/rx/rx.md @@ -0,0 +1,1766 @@ +;; Machine Description for Renesas RX processors +;; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +;; Contributed by Red Hat. + +;; 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 3, 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 COPYING3. If not see +;; . + + +;; This code iterator allows all branch instructions to +;; be generated from a single define_expand template. +(define_code_iterator most_cond [eq ne gt ge lt le gtu geu ltu leu + unordered ordered ]) + +;; This code iterator is used for sign- and zero- extensions. +(define_mode_iterator small_int_modes [(HI "") (QI "")]) + +;; We do not handle DFmode here because it is either +;; the same as SFmode, or if -m64bit-doubles is active +;; then all operations on doubles have to be handled by +;; library functions. +(define_mode_iterator register_modes + [(SF "ALLOW_RX_FPU_INSNS") (SI "") (HI "") (QI "")]) + + +;; Used to map RX condition names to GCC +;; condition names for builtin instructions. +(define_code_iterator gcc_conds [eq ne gt ge lt le gtu geu ltu leu + unge unlt uneq ltgt]) +(define_code_attr rx_conds [(eq "eq") (ne "ne") (gt "gt") (ge "ge") (lt "lt") + (le "le") (gtu "gtu") (geu "geu") (ltu "ltu") + (leu "leu") (unge "pz") (unlt "n") (uneq "o") + (ltgt "no")]) + +(define_constants + [ + (SP_REG 0) + + (UNSPEC_LOW_REG 0) + (UNSPEC_HIGH_REG 1) + + (UNSPEC_RTE 10) + (UNSPEC_RTFI 11) + (UNSPEC_NAKED 12) + + (UNSPEC_MOVSTR 20) + (UNSPEC_MOVMEM 21) + (UNSPEC_SETMEM 22) + (UNSPEC_STRLEN 23) + (UNSPEC_CMPSTRN 24) + + (UNSPEC_BUILTIN_BRK 30) + (UNSPEC_BUILTIN_CLRPSW 31) + (UNSPEC_BUILTIN_INT 32) + (UNSPEC_BUILTIN_MACHI 33) + (UNSPEC_BUILTIN_MACLO 34) + (UNSPEC_BUILTIN_MULHI 35) + (UNSPEC_BUILTIN_MULLO 36) + (UNSPEC_BUILTIN_MVFACHI 37) + (UNSPEC_BUILTIN_MVFACMI 38) + (UNSPEC_BUILTIN_MVFC 39) + (UNSPEC_BUILTIN_MVFCP 40) + (UNSPEC_BUILTIN_MVTACHI 41) + (UNSPEC_BUILTIN_MVTACLO 42) + (UNSPEC_BUILTIN_MVTC 43) + (UNSPEC_BUILTIN_MVTIPL 44) + (UNSPEC_BUILTIN_RACW 45) + (UNSPEC_BUILTIN_REVW 46) + (UNSPEC_BUILTIN_RMPA 47) + (UNSPEC_BUILTIN_ROUND 48) + (UNSPEC_BUILTIN_SAT 49) + (UNSPEC_BUILTIN_SETPSW 50) + (UNSPEC_BUILTIN_WAIT 51) + ] +) + +;; Condition code settings: +;; none - insn does not affect the condition code bits +;; set_zs - insn sets z,s to usable values; +;; set_zso - insn sets z,s,o to usable values; +;; set_zsoc - insn sets z,s,o,c to usable values; +;; clobber - value of cc0 is unknown +(define_attr "cc" "none,set_zs,set_zso,set_zsoc,clobber" (const_string "none")) + +(define_attr "length" "" (const_int 8)) + +(include "predicates.md") +(include "constraints.md") + +;; Pipeline description. + +;; The RX only has a single pipeline. It has five stages (fetch, +;; decode, execute, memory access, writeback) each of which normally +;; takes a single CPU clock cycle. + +;; The timings attribute consists of two numbers, the first is the +;; throughput, which is the number of cycles the instruction takes +;; to execute and generate a result. The second is the latency +;; which is the effective number of cycles the instruction takes to +;; execute if its result is used by the following instruction. The +;; latency is always greater than or equal to the throughput. +;; These values were taken from tables 2.13 and 2.14 in section 2.8 +;; of the RX610 Group Hardware Manual v0.11 + +;; Note - it would be nice to use strings rather than integers for +;; the possible values of this attribute, so that we can have the +;; gcc build mechanism check for values that are not supported by +;; the reservations below. But this will not work because the code +;; in rx_adjust_sched_cost() needs integers not strings. + +(define_attr "timings" "" (const_int 11)) + +(define_automaton "pipelining") +(define_cpu_unit "throughput" "pipelining") + +(define_insn_reservation "throughput__1_latency__1" 1 + (eq_attr "timings" "11") "throughput") +(define_insn_reservation "throughput__1_latency__2" 2 + (eq_attr "timings" "12") "throughput,nothing") +(define_insn_reservation "throughput__2_latency__2" 1 + (eq_attr "timings" "22") "throughput*2") +(define_insn_reservation "throughput__3_latency__3" 1 + (eq_attr "timings" "33") "throughput*3") +(define_insn_reservation "throughput__3_latency__4" 2 + (eq_attr "timings" "34") "throughput*3,nothing") +(define_insn_reservation "throughput__4_latency__4" 1 + (eq_attr "timings" "44") "throughput*4") +(define_insn_reservation "throughput__4_latency__5" 2 + (eq_attr "timings" "45") "throughput*4,nothing") +(define_insn_reservation "throughput__5_latency__5" 1 + (eq_attr "timings" "55") "throughput*5") +(define_insn_reservation "throughput__5_latency__6" 2 + (eq_attr "timings" "56") "throughput*5,nothing") +(define_insn_reservation "throughput__6_latency__6" 1 + (eq_attr "timings" "66") "throughput*6") +(define_insn_reservation "throughput_10_latency_10" 1 + (eq_attr "timings" "1010") "throughput*10") +(define_insn_reservation "throughput_11_latency_11" 1 + (eq_attr "timings" "1111") "throughput*11") +(define_insn_reservation "throughput_16_latency_16" 1 + (eq_attr "timings" "1616") "throughput*16") +(define_insn_reservation "throughput_18_latency_18" 1 + (eq_attr "timings" "1818") "throughput*18") + +;; Comparisons + +(define_expand "cbranchsi4" + [(set (cc0) (compare:CC (match_operand:SI 1 "register_operand") + (match_operand:SI 2 "rx_source_operand"))) + (set (pc) + (if_then_else (match_operator:SI 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "" + "" +) + +(define_expand "cbranchsf4" + [(set (cc0) (compare:CC (match_operand:SF 1 "register_operand") + (match_operand:SF 2 "rx_source_operand"))) + (set (pc) + (if_then_else (match_operator:SI 0 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 3 "")) + (pc)))] + "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions" + "" +) + +;; The TST instruction is not used as it does not set the Carry flag, +;; so for example, the LessThan comparison cannot be tested. +;; +;; (define_insn "tstsi" +;; [(set (cc0) +;; (match_operand:SI 0 "rx_source_operand" "r,i,Q")))] +;; "" +;; { +;; rx_float_compare_mode = false; +;; return "tst\t%Q0"; +;; } +;; [(set_attr "cc" "set_zs") +;; (set_attr "timings" "11,11,33") +;; (set_attr "length" "3,7,6")] +;; ) + +(define_insn "cmpsi" + [(set (cc0) (compare:CC + (match_operand:SI 0 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI 1 "rx_source_operand" + "r,Uint04,Int08,Sint16,Sint24,i,Q")))] + "" + { + rx_float_compare_mode = false; + return "cmp\t%Q1, %Q0"; + } + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,5")] +) + +;; This pattern is disabled when -fnon-call-exceptions is active because +;; it could generate a floating point exception, which would introduce an +;; edge into the flow graph between this insn and the conditional branch +;; insn to follow, thus breaking the cc0 relationship. Run the g++ test +;; g++.dg/eh/080514-1.C to see this happen. +(define_insn "cmpsf" + [(set (cc0) + (compare:CC (match_operand:SF 0 "register_operand" "r,r,r") + (match_operand:SF 1 "rx_source_operand" "r,i,Q")))] + "ALLOW_RX_FPU_INSNS && ! flag_non_call_exceptions" + { + rx_float_compare_mode = true; + return "fcmp\t%1, %0"; + } + [(set_attr "cc" "set_zso") + (set_attr "timings" "11,11,33") + (set_attr "length" "3,7,5")] +) + +;; Flow Control Instructions: + +(define_expand "b" + [(set (pc) + (if_then_else (most_cond (cc0) (const_int 0)) + (label_ref (match_operand 0)) + (pc)))] + "" + "" +) + +(define_insn "*conditional_branch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + { + return rx_gen_cond_branch_template (operands[1], false); + } + [(set_attr "length" "8") ;; This length is wrong, but it is + ;; too hard to compute statically. + (set_attr "timings" "33") ;; The timing assumes that the branch is taken. + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "*reveresed_conditional_branch" + [(set (pc) + (if_then_else (match_operator 1 "comparison_operator" + [(cc0) (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + { + return rx_gen_cond_branch_template (operands[1], true); + } + [(set_attr "length" "8") ;; This length is wrong, but it is + ;; too hard to compute statically. + (set_attr "timings" "33") ;; The timing assumes that the branch is taken. + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "jump" + [(set (pc) (label_ref (match_operand 0 "" "")))] + "" + "bra\t%0" + [(set_attr "length" "4") + (set_attr "timings" "33") + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "indirect_jump" + [(set (pc) (match_operand:SI 0 "register_operand" "r"))] + "" + "jmp\t%0" + [(set_attr "length" "2") + (set_attr "timings" "33") + (set_attr "cc" "clobber")] ;; FIXME: This clobber is wrong. +) + +(define_insn "tablejump" + [(set (pc) (match_operand:SI 0 "register_operand" "r")) + (use (label_ref (match_operand 1 "" "")))] + "" + { return flag_pic ? (TARGET_AS100_SYNTAX ? "\n?:\tbra\t%0" + : "\n1:\tbra\t%0") + : "jmp\t%0"; + } + [(set_attr "cc" "clobber") ;; FIXME: This clobber is wrong. + (set_attr "timings" "33") + (set_attr "length" "2")] +) + +(define_insn "simple_return" + [(return)] + "" + "rts" + [(set_attr "length" "1") + (set_attr "timings" "55")] +) + +(define_insn "deallocate_and_return" + [(set (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI 0 "immediate_operand" "i"))) + (return)] + "" + "rtsd\t%0" + [(set_attr "length" "2") + (set_attr "timings" "55")] +) + +(define_insn "pop_and_return" + [(match_parallel 1 "rx_rtsd_vector" + [(set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_popm (operands, false); + return ""; + } + [(set_attr "length" "3") + (set_attr "timings" "56")] +) + +(define_insn "fast_interrupt_return" + [(unspec_volatile [(return)] UNSPEC_RTFI) ] + "" + "rtfi" + [(set_attr "length" "2") + (set_attr "timings" "33")] +) + +(define_insn "exception_return" + [(unspec_volatile [(return)] UNSPEC_RTE) ] + "" + "rte" + [(set_attr "length" "2") + (set_attr "timings" "66")] +) + +(define_insn "naked_return" + [(unspec_volatile [(return)] UNSPEC_NAKED) ] + "" + "; Naked function: epilogue provided by programmer." +) + + +;; Note - the following set of patterns do not use the "memory_operand" +;; predicate or an "m" constraint because we do not allow symbol_refs +;; or label_refs as legitmate memory addresses. This matches the +;; behaviour of most of the RX instructions. Only the call/branch +;; instructions are allowed to refer to symbols/labels directly. +;; The call operands are in QImode because that is the value of +;; FUNCTION_MODE + +(define_expand "call" + [(call (match_operand:QI 0 "general_operand") + (match_operand:SI 1 "general_operand"))] + "" + { + rtx dest = XEXP (operands[0], 0); + + if (! rx_call_operand (dest, Pmode)) + dest = force_reg (Pmode, dest); + emit_call_insn (gen_call_internal (dest, operands[1])); + DONE; + } +) + +(define_insn "call_internal" + [(call (mem:QI (match_operand:SI 0 "rx_call_operand" "r,Symbol")) + (match_operand:SI 1 "general_operand" "g,g"))] + "" + "@ + jsr\t%A0 + bsr\t%A0" + [(set_attr "length" "2,4") + (set_attr "timings" "33")] +) + +(define_expand "call_value" + [(set (match_operand 0 "register_operand") + (call (match_operand:QI 1 "general_operand") + (match_operand:SI 2 "general_operand")))] + "" + { + rtx dest = XEXP (operands[1], 0); + + if (! rx_call_operand (dest, Pmode)) + dest = force_reg (Pmode, dest); + emit_call_insn (gen_call_value_internal (operands[0], dest, operands[2])); + DONE; + } +) + +(define_insn "call_value_internal" + [(set (match_operand 0 "register_operand" "=r,r") + (call (mem:QI (match_operand:SI 1 "rx_call_operand" "r,Symbol")) + (match_operand:SI 2 "general_operand" "g,g")))] + "" + "@ + jsr\t%A1 + bsr\t%A1" + [(set_attr "length" "2,4") + (set_attr "timings" "33")] +) + +(define_insn "sibcall" + [(call (mem:QI (match_operand:SI 0 "rx_symbolic_call_operand" "Symbol")) + (match_operand:SI 1 "general_operand" "g")) + (return) + (use (match_operand 2 "" ""))] + "" + "bra\t%A0" + [(set_attr "length" "4") + (set_attr "timings" "33")] +) + +(define_insn "sibcall_value" + [(set (match_operand 0 "register_operand" "=r") + (call (mem:QI (match_operand:SI 1 "rx_symbolic_call_operand" "Symbol")) + (match_operand:SI 2 "general_operand" "g"))) + (return) + (use (match_operand 3 "" ""))] + "" + "bra\t%A1" + [(set_attr "length" "4") + (set_attr "timings" "33")] +) + +;; Function Prologue/Epilogue Instructions + +(define_expand "prologue" + [(const_int 0)] + "" + "rx_expand_prologue (); DONE;" +) + +(define_expand "epilogue" + [(return)] + "" + "rx_expand_epilogue (false); DONE;" +) + +(define_expand "sibcall_epilogue" + [(return)] + "" + "rx_expand_epilogue (true); DONE;" +) + +;; Move Instructions + +;; Note - we do not allow memory to memory moves, even though the ISA +;; supports them. The reason is that the conditions on such moves are +;; too restrictive, specifically the source addressing mode is limited +;; by the destination addressing mode and vice versa. (For example it +;; is not possible to use indexed register indirect addressing for one +;; of the operands if the other operand is anything other than a register, +;; but it is possible to use register relative addressing when the other +;; operand also uses register relative or register indirect addressing). +;; +;; GCC does not support computing legitimate addresses based on the +;; nature of other operands involved in the instruction, and reload is +;; not smart enough to cope with a whole variety of different memory +;; addressing constraints, so it is simpler and safer to just refuse +;; to support memory to memory moves. + +(define_expand "mov" + [(set (match_operand:register_modes 0 "general_operand") + (match_operand:register_modes 1 "general_operand"))] + "" + { + if (MEM_P (operand0) && MEM_P (operand1)) + operands[1] = copy_to_mode_reg (mode, operand1); + } +) + +(define_insn "*mov_internal" + [(set (match_operand:register_modes + 0 "nonimmediate_operand" "=r,r,r,r,r,r,m,Q,Q,Q,Q") + (match_operand:register_modes + 1 "general_operand" "Int08,Sint16,Sint24,i,r,m,r,Int08,Sint16,Sint24,i"))] + "" + { return rx_gen_move_template (operands, false); } + [(set_attr "length" "3,4,5,6,2,4,6,5,6,7,8") + (set_attr "timings" "11,11,11,11,11,12,11,11,11,11,11")] +) + +(define_insn "extendsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (sign_extend:SI (match_operand:small_int_modes + 1 "nonimmediate_operand" "r,m")))] + "" + { return rx_gen_move_template (operands, false); } + [(set_attr "length" "2,6") + (set_attr "timings" "11,12")] +) + +(define_insn "zero_extendsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (zero_extend:SI (match_operand:small_int_modes + 1 "nonimmediate_operand" "r,m")))] + "" + { return rx_gen_move_template (operands, true); } + [(set_attr "length" "2,4") + (set_attr "timings" "11,12")] +) + +(define_insn "stack_push" + [(set:SI (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (const_int 4))) + (set:SI (mem:SI (reg:SI SP_REG)) + (match_operand:SI 0 "register_operand" "r"))] + "" + "push.l\t%0" + [(set_attr "length" "2")] +) + +(define_insn "stack_pushm" + [(match_parallel 1 "rx_store_multiple_vector" + [(set:SI (reg:SI SP_REG) + (minus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_pushm (operands); + return ""; + } + [(set_attr "length" "2") + (set_attr "timings" "44")] ;; The timing is a guesstimate average timing. +) + +(define_insn "stack_pop" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (mem:SI (reg:SI SP_REG))) + (set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (const_int 4)))] + "" + "pop\t%0" + [(set_attr "length" "2") + (set_attr "timings" "12")] +) + +(define_insn "stack_popm" + [(match_parallel 1 "rx_load_multiple_vector" + [(set:SI (reg:SI SP_REG) + (plus:SI (reg:SI SP_REG) + (match_operand:SI + 0 "const_int_operand" "n")))])] + "reload_completed" + { + rx_emit_stack_popm (operands, true); + return ""; + } + [(set_attr "length" "2") + (set_attr "timings" "45")] ;; The timing is a guesstimate average timing. +) + +(define_insn "cstoresi4" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") + (match_operator:SI + 1 "comparison_operator" + [(match_operand:SI + 2 "register_operand" "r,r,r,r,r,r,r") + (match_operand:SI + 3 "rx_source_operand" "r,Uint04,Int08,Sint16,Sint24,i,Q")]))] + "" + { + rx_float_compare_mode = false; + return "cmp\t%Q3, %Q2\n\tsc%B1.L\t%0"; + } + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,22,22,22,22,22,44") + (set_attr "length" "5,5,6,7,8,9,8")] +) + +(define_expand "movsicc" + [(set (match_operand:SI 0 "register_operand") + (if_then_else:SI (match_operand:SI 1 "comparison_operator") + (match_operand:SI 2 "nonmemory_operand") + (match_operand:SI 3 "immediate_operand")))] + "" + { + if (GET_CODE (operands[1]) != EQ && GET_CODE (operands[1]) != NE) + FAIL; + if (! CONST_INT_P (operands[3])) + FAIL; + } +) + +(define_insn "*movsieq" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (if_then_else:SI (eq (match_operand:SI + 3 "register_operand" "r,r,r") + (match_operand:SI + 4 "rx_source_operand" "riQ,riQ,riQ")) + (match_operand:SI + 1 "nonmemory_operand" "0,i,r") + (match_operand:SI + 2 "immediate_operand" "i,i,i")))] + "" + "@ + cmp\t%Q4, %Q3\n\tstnz\t%2, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstz\t%1, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstnz\t%2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "13,19,15") + (set_attr "timings" "22,33,33")] +) + +(define_insn "*movsine" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (if_then_else:SI (ne (match_operand:SI 3 "register_operand" "r,r,r") + (match_operand:SI 4 "rx_source_operand" "riQ,riQ,riQ")) + (match_operand:SI 1 "nonmemory_operand" "0,i,r") + (match_operand:SI 2 "immediate_operand" "i,i,i")))] + "" + "@ + cmp\t%Q4, %Q3\n\tstz\t%2, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%2, %0\n\tstnz\t%1, %0 + cmp\t%Q4, %Q3\n\tmov.l\t%1, %0\n\tstz\t%2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "13,19,15") + (set_attr "timings" "22,33,33")] +) + +;; Arithmetic Instructions + +(define_insn "abssi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (abs:SI (match_operand:SI 1 "register_operand" "0,r")))] + "" + "@ + abs\t%0 + abs\t%1, %0" + [(set_attr "cc" "set_zso") + (set_attr "length" "2,3")] +) + +(define_insn "addsi3" + [(set (match_operand:SI 0 "register_operand" + "=r,r,r,r,r,r,r,r,r,r,r,r") + (plus:SI (match_operand:SI + 1 "register_operand" + "%0,0,0,0,0,0,r,r,r,r,r,0") + (match_operand:SI + 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Sint08,Sint16,Sint24,i,Q")))] + "" + "@ + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%2, %1, %0 + add\t%Q2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,11,11,11,11,11,11,11,33") + (set_attr "length" "2,2,3,4,5,6,3,3,4,5,6,5")] +) + +(define_insn "adddi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") + (plus:DI (match_operand:DI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:DI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "add\t%L2, %L0\n\tadc\t%H2, %H0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,22,22,22,22,44") + (set_attr "length" "5,7,9,11,13,11")] +) + +(define_insn "andsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (and:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,0,Q") + (match_operand:SI + 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))] + "" + "@ + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %0 + and\t%2, %1, %0 + and\t%Q2, %0 + and\t%Q1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,11,11,33,33") + (set_attr "length" "2,2,3,4,5,6,3,5,5")] +) + +;; Byte swap (single 32-bit value). +(define_insn "bswapsi2" + [(set (match_operand:SI 0 "register_operand" "+r") + (bswap:SI (match_operand:SI 1 "register_operand" "r")))] + "" + "revl\t%1, %0" + [(set_attr "length" "3")] +) + +;; Byte swap (single 16-bit value). Note - we ignore the swapping of the high 16-bits. +(define_insn "bswaphi2" + [(set (match_operand:HI 0 "register_operand" "+r") + (bswap:HI (match_operand:HI 1 "register_operand" "r")))] + "" + "revw\t%1, %0" + [(set_attr "length" "3")] +) + +(define_insn "divsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (div:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") + (match_operand:SI + 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "div\t%Q2, %0" + [(set_attr "cc" "clobber") + (set_attr "timings" "1111") ;; Strictly speaking the timing should be + ;; 2222, but that is a worst case sceanario. + (set_attr "length" "3,4,5,6,7,6")] +) + +(define_insn "udivsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (udiv:SI (match_operand:SI 1 "register_operand" "0,0,0,0,0,0") + (match_operand:SI + 2 "rx_source_operand" "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "divu\t%Q2, %0" + [(set_attr "cc" "clobber") + (set_attr "timings" "1010") ;; Strictly speaking the timing should be + ;; 2020, but that is a worst case sceanario. + (set_attr "length" "3,4,5,6,7,6")] +) + +;; Note - these patterns are suppressed in big-endian mode because they +;; generate a little endian result. ie the most significant word of the +;; result is placed in the higher numbered register of the destination +;; register pair. + +(define_insn "mulsidi3" + [(set (match_operand:DI 0 "register_operand" "=r,r,r,r,r,r") + (mult:DI (sign_extend:DI (match_operand:SI + 1 "register_operand" "%0,0,0,0,0,0")) + (sign_extend:DI (match_operand:SI + 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q"))))] + "! TARGET_BIG_ENDIAN_DATA" + "@ + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0 + emul\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6") + (set_attr "timings" "22,22,22,22,22,44")] +) + +;; See comment for mulsidi3. +;; Note - the zero_extends are to distinguish this pattern from the +;; mulsidi3 pattern. Immediate mode addressing is not supported +;; because gcc cannot handle the expression: (zero_extend (const_int)). +(define_insn "umulsidi3" + [(set (match_operand:DI 0 "register_operand" + "=r,r") + (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" + "%0,0")) + (zero_extend:DI (match_operand:SI 2 "rx_compare_operand" + "r,Q"))))] + "! TARGET_BIG_ENDIAN_DATA" + "@ + emulu\t%Q2, %0 + emulu\t%Q2, %0" + [(set_attr "length" "3,6") + (set_attr "timings" "22,44")] +) + +(define_insn "smaxsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (smax:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "max\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6") + (set_attr "timings" "11,11,11,11,11,33")] +) + +(define_insn "sminsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r") + (smin:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q,r")))] + "" + "@ + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + min\t%Q2, %0 + mov.l\t%1,%0\n\tmin\t%Q2, %0" + [(set_attr "length" "3,4,5,6,7,6,5") + (set_attr "timings" "11,11,11,11,11,33,22")] +) + +(define_insn "mulsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (mult:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,0,Q,r") + (match_operand:SI 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,Q,0,r")))] + "" + "@ + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q2, %0 + mul\t%Q1, %0 + mul\t%Q2, %1, %0" + [(set_attr "length" "2,2,3,4,5,6,5,5,3") + (set_attr "timings" "11,11,11,11,11,11,33,33,11")] +) + +(define_insn "negsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (neg:SI (match_operand:SI 1 "register_operand" "0,r")))] + ;; The NEG instruction does not comply with -fwrapv semantics. + ;; See gcc.c-torture/execute/pr22493-1.c for an example of this. + "! flag_wrapv" + "@ + neg\t%0 + neg\t%1, %0" + [(set_attr "length" "2,3")] +) + +(define_insn "one_cmplsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (not:SI (match_operand:SI 1 "register_operand" "0,r")))] + "" + "@ + not\t%0 + not\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "2,3")] +) + +(define_insn "iorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r,r,r,r") + (ior:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0,r,0,Q") + (match_operand:SI 2 "rx_source_operand" + "r,Uint04,Sint08,Sint16,Sint24,i,r,Q,0")))] + "" + "@ + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %0 + or\t%2, %1, %0 + or\t%Q2, %0 + or\t%Q1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,11,11,33,33") + (set_attr "length" "2,2,3,4,5,6,3,5,5")] +) + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotate:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn")))] + "" + "rotl\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "3")] +) + +(define_insn "rotrsi3" + [(set (match_operand:SI 0 "register_operand" "=r") + (rotatert:SI (match_operand:SI 1 "register_operand" "0") + (match_operand:SI 2 "rx_shift_operand" "rn")))] + "" + "rotr\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "length" "3")] +) + +(define_insn "ashrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shar\t%2, %0 + shar\t%2, %0 + shar\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "lshrsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shlr\t%2, %0 + shlr\t%2, %0 + shlr\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "ashlsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r") + (ashift:SI (match_operand:SI 1 "register_operand" "0,0,r") + (match_operand:SI 2 "rx_shift_operand" "r,n,n")))] + "" + "@ + shll\t%2, %0 + shll\t%2, %0 + shll\t%2, %1, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "length" "3,2,3")] +) + +(define_insn "subsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r") + (minus:SI (match_operand:SI 1 "register_operand" "0,0,0,r,0") + (match_operand:SI 2 "rx_source_operand" "r,Uint04,n,r,Q")))] + "" + "@ + sub\t%2, %0 + sub\t%2, %0 + add\t%N2, %0 + sub\t%2, %1, %0 + sub\t%Q2, %0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "11,11,11,11,33") + (set_attr "length" "2,2,6,3,5")] +) + +(define_insn "subdi3" + [(set (match_operand:DI 0 "register_operand" "=r,r") + (minus:DI (match_operand:DI 1 "register_operand" "0,0") + (match_operand:DI 2 "rx_source_operand" "r,Q")))] + "" + "sub\t%L2, %L0\n\tsbb\t%H2, %H0" + [(set_attr "cc" "set_zsoc") + (set_attr "timings" "22,44") + (set_attr "length" "5,11")] +) + +(define_insn "xorsi3" + [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r,r") + (xor:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0,0") + (match_operand:SI 2 "rx_source_operand" + "r,Sint08,Sint16,Sint24,i,Q")))] + "" + "@ + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0 + xor\t%Q2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "11,11,11,11,11,33") + (set_attr "length" "3,4,5,6,7,6")] +) + +;; Floating Point Instructions + +(define_insn "addsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (plus:SF (match_operand:SF 1 "register_operand" "%0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "@ + fadd\t%2, %0 + fadd\t%2, %0 + fadd\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "44,44,66") + (set_attr "length" "3,7,5")] +) + +(define_insn "divsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (div:SF (match_operand:SF 1 "register_operand" "0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "fdiv\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "1616,1616,1818") + (set_attr "length" "3,7,5")] +) + +(define_insn "mulsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (mult:SF (match_operand:SF 1 "register_operand" "%0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "@ + fmul\t%2, %0 + fmul\t%2, %0 + fmul\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "33,33,55") + (set_attr "length" "3,7,5")] +) + +(define_insn "subsf3" + [(set (match_operand:SF 0 "register_operand" "=r,r,r") + (minus:SF (match_operand:SF 1 "register_operand" "0,0,0") + (match_operand:SF 2 "rx_source_operand" "r,F,Q")))] + "ALLOW_RX_FPU_INSNS" + "fsub\t%2, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "44,44,66") + (set_attr "length" "3,7,5")] +) + +(define_insn "fix_truncsfsi2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (fix:SI (match_operand:SF 1 "rx_compare_operand" "r,Q")))] + "ALLOW_RX_FPU_INSNS" + "ftoi\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,5")] +) + +(define_insn "floatsisf2" + [(set (match_operand:SF 0 "register_operand" "=r,r") + (float:SF (match_operand:SI 1 "rx_compare_operand" "r,Q")))] + "ALLOW_RX_FPU_INSNS" + "itof\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,6")] +) + +;; Bit manipulation instructions. +;; Note - there are two versions of each pattern because the memory +;; accessing versions use QImode whilst the register accessing +;; versions use SImode. +;; The peephole are here because the combiner only looks at a maximum +;; of three instructions at a time. + +(define_insn "bitset" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (ior:SI (match_operand:SI 1 "register_operand" "0") + (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri"))))] + "" + "bset\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitset_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (ior:QI (match_operand:QI 1 "memory_operand" "0") + (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri"))))] + "" + "bset\t%2, %0.B" + [(set_attr "length" "3") + (set_attr "timings" "34")] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg C) (ior (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (ior:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (ior:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg A) (ior (reg A) (reg C))) +;; (set (reg C) (reg A) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (ior:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (ior:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] +) + +(define_insn "bitinvert" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (xor:SI (match_operand:SI 1 "register_operand" "0") + (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri"))))] + "" + "bnot\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitinvert_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (xor:QI (match_operand:QI 1 "register_operand" "0") + (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri"))))] + "" + "bnot\t%2, %0.B" + [(set_attr "length" "5") + (set_attr "timings" "33")] +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg C) (xor (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (xor:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (xor:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] + "" +) + +;; (set (reg A) (const_int 1)) +;; (set (reg A) (ashift (reg A) (reg B))) +;; (set (reg A) (xor (reg A) (reg C))) +;; (set (reg C) (reg A)) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int 1)) + (set:SI (match_dup 0) + (ashift:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (xor:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (xor:SI (match_dup 2) + (ashift:SI (const_int 1) + (match_dup 1))))] + "" +) + +(define_insn "bitclr" + [(set:SI (match_operand:SI 0 "register_operand" "+r") + (and:SI (match_operand:SI 1 "register_operand" "0") + (not:SI (ashift:SI (const_int 1) + (match_operand:SI 2 "nonmemory_operand" "ri")))))] + "" + "bclr\t%2, %0" + [(set_attr "length" "3")] +) + +(define_insn "bitclr_in_memory" + [(set:QI (match_operand:QI 0 "memory_operand" "+m") + (and:QI (match_operand:QI 1 "memory_operand" "0") + (not:QI (ashift:QI (const_int 1) + (match_operand:QI 2 "nonmemory_operand" "ri")))))] + "" + "bclr\t%2, %0.B" + [(set_attr "length" "3") + (set_attr "timings" "34")] +) + +;; (set (reg A) (const_int -2)) +;; (set (reg A) (rotate (reg A) (reg B))) +;; (set (reg C) (and (reg A) (reg C))) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int -2)) + (set:SI (match_dup 0) + (rotate:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_operand:SI 2 "register_operand" "") + (and:SI (match_dup 0) + (match_dup 2)))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (and:SI (match_dup 2) + (not:SI (ashift:SI (const_int 1) + (match_dup 1)))))] +) + +;; (set (reg A) (const_int -2)) +;; (set (reg A) (rotate (reg A) (reg B))) +;; (set (reg A) (and (reg A) (reg C))) +;; (set (reg C) (reg A) +(define_peephole2 + [(set:SI (match_operand:SI 0 "register_operand" "") + (const_int -2)) + (set:SI (match_dup 0) + (rotate:SI (match_dup 0) + (match_operand:SI 1 "register_operand" ""))) + (set:SI (match_dup 0) + (and:SI (match_dup 0) + (match_operand:SI 2 "register_operand" ""))) + (set:SI (match_dup 2) (match_dup 0))] + "dead_or_set_p (insn, operands[0])" + [(set:SI (match_dup 2) + (and:SI (match_dup 2) + (not:SI (ashift:SI (const_int 1) + (match_dup 1)))))] +) + +(define_expand "insv" + [(set:SI (zero_extract:SI (match_operand:SI + 0 "nonimmediate_operand") ;; Destination + (match_operand + 1 "immediate_operand") ;; # of bits to set + (match_operand + 2 "immediate_operand")) ;; Starting bit + (match_operand + 3 "immediate_operand"))] ;; Bits to insert + "" + { + if (rx_expand_insv (operands)) + DONE; + FAIL; + } +) + +;; Atomic exchange operation. + +(define_insn "sync_lock_test_and_setsi" + [(set:SI (match_operand:SI 0 "register_operand" "=r,r") + (match_operand:SI 1 "rx_compare_operand" "=r,Q")) + (set:SI (match_dup 1) + (match_operand:SI 2 "register_operand" "0,0"))] + "" + "xchg\t%1, %0" + [(set_attr "length" "3,6") + (set_attr "timings" "22")] +) + +;; Block move functions. + +(define_expand "movstr" + [(set:SI (match_operand:BLK 1 "memory_operand") ;; Dest + (match_operand:BLK 2 "memory_operand")) ;; Source + (use (match_operand:SI 0 "register_operand")) ;; Updated Dest + ] + "" + { + rtx addr1 = gen_rtx_REG (SImode, 1); + rtx addr2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + rtx dest_copy = gen_reg_rtx (SImode); + + emit_move_insn (len, GEN_INT (-1)); + emit_move_insn (addr1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (addr2, force_operand (XEXP (operands[2], 0), NULL_RTX)); + operands[1] = replace_equiv_address_nv (operands[1], addr1); + operands[2] = replace_equiv_address_nv (operands[2], addr2); + emit_move_insn (dest_copy, addr1); + emit_insn (gen_rx_movstr ()); + emit_move_insn (len, GEN_INT (-1)); + emit_insn (gen_rx_strend (operands[0], dest_copy)); + DONE; + } +) + +(define_insn "rx_movstr" + [(set:SI (mem:BLK (reg:SI 1)) + (mem:BLK (reg:SI 2))) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVSTR) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + ] + "" + "smovu" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_insn "rx_strend" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(match_operand:SI 1 "register_operand" "r") + (reg:SI 3)] UNSPEC_STRLEN)) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3)) + ] + "" + "mov\t%1, r1\n\tmov\t#0, r2\n\tsuntil.b\n\tmov\tr1, %0\n\tsub\t#1, %0" + [(set_attr "length" "10") + (set_attr "cc" "clobber") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "movmemsi" + [(parallel + [(set (match_operand:BLK 0 "memory_operand") ;; Dest + (match_operand:BLK 1 "memory_operand")) ;; Source + (use (match_operand:SI 2 "register_operand")) ;; Length in bytes + (match_operand 3 "immediate_operand") ;; Align + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM)] + )] + "" + { + rtx addr1 = gen_rtx_REG (SImode, 1); + rtx addr2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + if (REG_P (operands[0]) && (REGNO (operands[0]) == 2 + || REGNO (operands[0]) == 3)) + FAIL; + if (REG_P (operands[1]) && (REGNO (operands[1]) == 1 + || REGNO (operands[1]) == 3)) + FAIL; + if (REG_P (operands[2]) && (REGNO (operands[2]) == 1 + || REGNO (operands[2]) == 2)) + FAIL; + emit_move_insn (addr1, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (addr2, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[2], NULL_RTX)); + operands[0] = replace_equiv_address_nv (operands[0], addr1); + operands[1] = replace_equiv_address_nv (operands[1], addr2); + emit_insn (gen_rx_movmem ()); + DONE; + } +) + +(define_insn "rx_movmem" + [(set (mem:BLK (reg:SI 1)) + (mem:BLK (reg:SI 2))) + (use (reg:SI 3)) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_MOVMEM) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "smovf" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "setmemsi" + [(set (match_operand:BLK 0 "memory_operand") ;; Dest + (match_operand:QI 2 "nonmemory_operand")) ;; Value + (use (match_operand:SI 1 "nonmemory_operand")) ;; Length + (match_operand 3 "immediate_operand") ;; Align + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM)] + "" + { + rtx addr = gen_rtx_REG (SImode, 1); + rtx val = gen_rtx_REG (QImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (addr, force_operand (XEXP (operands[0], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[1], NULL_RTX)); + emit_move_insn (val, operands[2]); + emit_insn (gen_rx_setmem ()); + DONE; + } +) + +(define_insn "rx_setmem" + [(set:BLK (mem:BLK (reg:SI 1)) (reg 2)) + (unspec_volatile:BLK [(reg:SI 1) (reg:SI 2) (reg:SI 3)] UNSPEC_SETMEM) + (clobber (reg:SI 1)) + (clobber (reg:SI 3))] + "" + "sstr.b" + [(set_attr "length" "2") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +(define_expand "cmpstrnsi" + [(set (match_operand:SI + 0 "register_operand") ;; Result + (unspec_volatile:SI [(match_operand:BLK + 1 "memory_operand") ;; String1 + (match_operand:BLK + 2 "memory_operand")] ;; String2 + UNSPEC_CMPSTRN)) + (use (match_operand:SI + 3 "register_operand")) ;; Max Length + (match_operand:SI + 4 "immediate_operand")] ;; Known Align + "" + { + rtx str1 = gen_rtx_REG (SImode, 1); + rtx str2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (str1, force_operand (XEXP (operands[1], 0), NULL_RTX)); + emit_move_insn (str2, force_operand (XEXP (operands[2], 0), NULL_RTX)); + emit_move_insn (len, force_operand (operands[3], NULL_RTX)); + + emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); + DONE; + } +) + +(define_expand "cmpstrsi" + [(set (match_operand:SI + 0 "register_operand") ;; Result + (unspec_volatile:SI [(match_operand:BLK + 1 "memory_operand") ;; String1 + (match_operand:BLK + 2 "memory_operand")] ;; String2 + UNSPEC_CMPSTRN)) + (match_operand:SI + 3 "immediate_operand")] ;; Known Align + "" + { + rtx str1 = gen_rtx_REG (SImode, 1); + rtx str2 = gen_rtx_REG (SImode, 2); + rtx len = gen_rtx_REG (SImode, 3); + + emit_move_insn (str1, force_reg (SImode, XEXP (operands[1], 0))); + emit_move_insn (str2, force_reg (SImode, XEXP (operands[2], 0))); + emit_move_insn (len, GEN_INT (-1)); + + emit_insn (gen_rx_cmpstrn (operands[0], operands[1], operands[2])); + DONE; + } +) + +(define_insn "rx_cmpstrn" + [(set:SI (match_operand:SI 0 "register_operand" "=r") + (unspec_volatile:SI [(reg:SI 1) (reg:SI 2) (reg:SI 3)] + UNSPEC_CMPSTRN)) + (use (match_operand:BLK 1 "memory_operand" "m")) + (use (match_operand:BLK 2 "memory_operand" "m")) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "scmpu ; Perform the string comparison + mov #-1, %0 ; Set up -1 result (which cannot be created + ; by the SC insn) + bnc ?+ ; If Carry is not set skip over + scne.L %0 ; Set result based on Z flag +?: +" + [(set_attr "length" "9") + (set_attr "timings" "1111")] ;; The timing is a guesstimate. +) + +;; Builtin Functions +;; +;; GCC does not have the ability to generate the following instructions +;; on its own so they are provided as builtins instead. To use them from +;; a program for example invoke them as __builtin_rx_. For +;; example: +;; +;; int short_byte_swap (int arg) { return __builtin_rx_revw (arg); } + +;;---------- Accumulator Support ------------------------ + +;; Multiply & Accumulate (high) +(define_insn "machi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MACHI)] + "" + "machi\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply & Accumulate (low) +(define_insn "maclo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MACLO)] + "" + "maclo\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply (high) +(define_insn "mulhi" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MULHI)] + "" + "mulhi\t%0, %1" + [(set_attr "length" "3")] +) + +;; Multiply (low) +(define_insn "mullo" + [(unspec:SI [(match_operand:SI 0 "register_operand" "r") + (match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_MULLO)] + "" + "mullo\t%0, %1" + [(set_attr "length" "3")] +) + +;; Move from Accumulator (high) +(define_insn "mvfachi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] + UNSPEC_BUILTIN_MVFACHI))] + "" + "mvfachi\t%0" + [(set_attr "length" "3")] +) + +;; Move from Accumulator (middle) +(define_insn "mvfacmi" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(const_int 0)] + UNSPEC_BUILTIN_MVFACMI))] + "" + "mvfacmi\t%0" + [(set_attr "length" "3")] +) + +;; Move to Accumulator (high) +(define_insn "mvtachi" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_BUILTIN_MVTACHI)] + "" + "mvtachi\t%0" + [(set_attr "length" "3")] +) + +;; Move to Accumulator (low) +(define_insn "mvtaclo" + [(unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")] + UNSPEC_BUILTIN_MVTACLO)] + "" + "mvtaclo\t%0" + [(set_attr "length" "3")] +) + +;; Round Accumulator +(define_insn "racw" + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_RACW)] + "" + "racw\t%0" + [(set_attr "length" "3")] +) + +;; Repeat multiply and accumulate +(define_insn "rmpa" + [(unspec:SI [(const_int 0) (reg:SI 1) (reg:SI 2) (reg:SI 3) + (reg:SI 4) (reg:SI 5) (reg:SI 6)] + UNSPEC_BUILTIN_RMPA) + (clobber (reg:SI 1)) + (clobber (reg:SI 2)) + (clobber (reg:SI 3))] + "" + "rmpa" + [(set_attr "length" "2") + (set_attr "timings" "1010")] +) + +;;---------- Arithmetic ------------------------ + +;; Byte swap (two 16-bit values). +(define_insn "revw" + [(set (match_operand:SI 0 "register_operand" "+r") + (unspec:SI [(match_operand:SI 1 "register_operand" "r")] + UNSPEC_BUILTIN_REVW))] + "" + "revw\t%1, %0" + [(set_attr "length" "3")] +) + +;; Round to integer. +(define_insn "lrintsf2" + [(set (match_operand:SI 0 "register_operand" "=r,r") + (unspec:SI [(match_operand:SF 1 "rx_compare_operand" "r,Q")] + UNSPEC_BUILTIN_ROUND))] + "" + "round\t%1, %0" + [(set_attr "cc" "set_zs") + (set_attr "timings" "22,44") + (set_attr "length" "3,5")] +) + +;; Saturate to 32-bits +(define_insn "sat" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "register_operand" "0")] + UNSPEC_BUILTIN_SAT))] + "" + "sat\t%0" + [(set_attr "length" "2")] +) + +;;---------- Control Registers ------------------------ + +;; Clear Processor Status Word +(define_insn "clrpsw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_CLRPSW) + (clobber (cc0))] + "" + "clrpsw\t%F0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")] +) + +;; Set Processor Status Word +(define_insn "setpsw" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_SETPSW) + (clobber (cc0))] + "" + "setpsw\t%F0" + [(set_attr "length" "2") + (set_attr "cc" "clobber")] +) + +;; Move from control register +(define_insn "mvfc" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "immediate_operand" "i")] + UNSPEC_BUILTIN_MVFC))] + "" + "mvfc\t%C1, %0" + [(set_attr "length" "3")] +) + +;; Move to control register +(define_insn "mvtc" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "i,i") + (match_operand:SI 1 "nonmemory_operand" "r,i")] + UNSPEC_BUILTIN_MVTC)] + "" + "mvtc\t%1, %C0" + [(set_attr "length" "3,7")] + ;; Ignore possible clobbering of the comparison flags in the + ;; PSW register. This is a cc0 target so any cc0 setting + ;; instruction will always be paired with a cc0 user, without + ;; the possibility of this instruction being placed in between + ;; them. +) + +;; Move to interrupt priority level +(define_insn "mvtipl" + [(unspec:SI [(match_operand:SI 0 "immediate_operand" "Uint04")] + UNSPEC_BUILTIN_MVTIPL)] + "" + "mvtipl\t%0" + [(set_attr "length" "3")] +) + +;;---------- Interrupts ------------------------ + +;; Break +(define_insn "brk" + [(unspec_volatile [(const_int 0)] + UNSPEC_BUILTIN_BRK)] + "" + "brk" + [(set_attr "length" "1") + (set_attr "timings" "66")] +) + +;; Interrupt +(define_insn "int" + [(unspec_volatile:SI [(match_operand:SI 0 "immediate_operand" "i")] + UNSPEC_BUILTIN_INT)] + "" + "int\t%0" + [(set_attr "length" "3")] +) + +;; Wait +(define_insn "wait" + [(unspec_volatile [(const_int 0)] + UNSPEC_BUILTIN_WAIT)] + "" + "wait" + [(set_attr "length" "2")] +) + +;;---------- CoProcessor Support ------------------------ + +;; FIXME: The instructions are currently commented out because +;; the bit patterns have not been finalized, so the assembler +;; does not support them. Once they are decided and the assembler +;; supports them, enable the instructions here. + +;; Move from co-processor register +(define_insn "mvfcp" + [(set (match_operand:SI 0 "register_operand" "=r") + (unspec:SI [(match_operand:SI 1 "immediate_operand" "i") + (match_operand:SI 2 "immediate_operand" "i")] + UNSPEC_BUILTIN_MVFCP))] + "" + "; mvfcp\t%1, %0, %2" + [(set_attr "length" "5")] +) + +;;---------- Misc ------------------------ + +;; Required by cfglayout.c... +(define_insn "nop" + [(const_int 0)] + "" + "nop" + [(set_attr "length" "1")] +) diff --git a/gcc/config/rx/rx.opt b/gcc/config/rx/rx.opt new file mode 100644 index 00000000000..768d565b478 --- /dev/null +++ b/gcc/config/rx/rx.opt @@ -0,0 +1,98 @@ +; Command line options for the Renesas RX port of GCC. +; Copyright (C) 2008, 2009 Free Software Foundation, Inc. +; Contributed by Red Hat. +; +; 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 3, 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 COPYING3. If not see +; . +;--------------------------------------------------- + +m32bit-doubles +Target RejectNegative Mask(32BIT_DOUBLES) +Stores doubles in 32 bits. + +m64bit-doubles +Target RejectNegative InverseMask(32BIT_DOUBLES) +Store doubles in 64 bits. This is the default. + +fpu +Target RejectNegative Mask(32BIT_DOUBLES) MaskExists +Enable the use of RX FPU instructions. + +nofpu +Target RejectNegative InverseMask(32BIT_DOUBLES) MaskExists +Disable the use of RX FPU instructions. + +;--------------------------------------------------- + +mcpu= +Target RejectNegative Joined Var(rx_cpu_name) +Specify the target RX cpu type. + +patch= +Target RejectNegative Joined Var(rx_cpu_name) +Alias for -mcpu. + +;--------------------------------------------------- + +mbig-endian-data +Target RejectNegative Mask(BIG_ENDIAN_DATA) +Data is stored in big-endian format. + +mlittle-endian-data +Target RejectNegative InverseMask(BIG_ENDIAN_DATA) +Data is stored in little-endian format. (Default). + +;--------------------------------------------------- + +msmall-data-limit= +Target RejectNegative Joined UInteger Var(rx_small_data_limit) Init(0) +Maximum size of global and static variables which can be placed into the small data area. + +;--------------------------------------------------- + +msim +Target +Use the simulator runtime. + +;--------------------------------------------------- + +mas100-syntax +Target Mask(AS100_SYNTAX) +Generate assembler output that is compatible with the Renesas AS100 assembler. This may restrict some of the compiler's capabilities. The default is to generate GAS compatable syntax. + +;--------------------------------------------------- + +mrelax +Target +Enable linker relaxation. + +;--------------------------------------------------- + +mmax-constant-size= +Target RejectNegative Joined UInteger Var(rx_max_constant_size) Init(0) +Maximum size in bytes of constant values allowed as operands. + +;--------------------------------------------------- + +mint-register= +Target RejectNegative Joined UInteger Var(rx_interrupt_registers) Init(0) +Specifies the number of registers to reserve for interrupt handlers. + +;--------------------------------------------------- + +msave-acc-in-interrupts +Target Mask(SAVE_ACC_REGISTER) +Specifies whether interrupt functions should save and restore the accumulator register. diff --git a/gcc/config/rx/t-rx b/gcc/config/rx/t-rx new file mode 100644 index 00000000000..eb1ca48d3a3 --- /dev/null +++ b/gcc/config/rx/t-rx @@ -0,0 +1,32 @@ +# Makefile fragment for building GCC for the Renesas RX target. +# Copyright (C) 2008, 2009 Free Software Foundation, Inc. +# Contributed by Red Hat. +# +# 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 3, 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 COPYING3. If not see +# . + +# Enable multilibs: + +MULTILIB_OPTIONS = m32bit-doubles mbig-endian-data +MULTILIB_DIRNAMES = 32fp big-endian-data +MULTILIB_MATCHES = m32bit-doubles=fpu +MULTILIB_EXCEPTIONS = +MULTILIB_EXTRA_OPTS = + +LIBGCC = stmp-multilib +INSTALL_LIBGCC = install-multilib + +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o diff --git a/gcc/config/s390/2097.md b/gcc/config/s390/2097.md index eb7240effd4..56893596a74 100644 --- a/gcc/config/s390/2097.md +++ b/gcc/config/s390/2097.md @@ -57,7 +57,8 @@ z10_int_fr_A3" "z10_other_super, z10_other_super_c_E1, z10_other_super_E1, \ z10_int_super, z10_int_super_E1, \ - z10_lr, z10_store_super") + z10_lr, z10_store_super" + " ! s390_agen_dep_p") ; Forwarding from z10_super to frz10_ and z10_rec. @@ -68,7 +69,8 @@ z10_store_super" "z10_int_fr, z10_int_fr_E1, z10_int_fr_A3, \ z10_other_fr, z10_other_fr_A3, z10_lr_fr, z10_lr_fr_E1, \ - z10_other_fr_E1, z10_store_rec") + z10_other_fr_E1, z10_store_rec" + " ! s390_agen_dep_p") ; Forwarding from z10_fwd and z10_fr to z10_rec and z10_fr. @@ -84,7 +86,8 @@ z10_int_fr_A3" "z10_int_fr, z10_int_fr_E1, z10_int_fr_A3, \ z10_other_fr, z10_other_fr_A3, z10_lr_fr, z10_lr_fr_E1, \ - z10_other_fr_E1, z10_store_rec") + z10_other_fr_E1, z10_store_rec" + " ! s390_agen_dep_p") ; @@ -205,15 +208,12 @@ (and (eq_attr "type" "lr") (eq_attr "z10prop" "z10_fr"))) "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") (define_insn_reservation "z10_lr_fr_E1" 6 (and (eq_attr "cpu" "z10") (and (eq_attr "type" "lr") (eq_attr "z10prop" "z10_fr_E1"))) "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") - (define_insn_reservation "z10_la" 6 (and (eq_attr "cpu" "z10") @@ -227,14 +227,12 @@ (and (eq_attr "type" "la") (eq_attr "z10prop" "z10_fwd"))) "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") (define_insn_reservation "z10_la_fwd_A1" 6 (and (eq_attr "cpu" "z10") (and (eq_attr "type" "la") (eq_attr "z10prop" "z10_fwd_A1"))) "z10_e1_ANY, z10_Gate_ANY") -; "z10_e1_ANY") ; larl-type instructions @@ -666,13 +664,14 @@ ; Address-related bypasses ; -; Here is the cycle diagram for Address-related bypasses: +; Here is the cycle diagram for address-related bypasses: ; ... G1 G2 G3 A0 A1 A2 A3 E1 P1 P2 P3 R0 ... -; ^ ^ ^ ^ ^ -; | | | | E1-type bypasses provide the new addr AFTER this cycle -; | | | A3-type bypasses provide the new addr AFTER this cycle -; | | A1-type bypasses provide the new addr AFTER this cycle -; | AGI resolution, actual USE of address is DURING this cycle +; ^ ^ ^ ^ ^ ^ +; | | | | | without bypass, its available AFTER this cycle +; | | | | E1-type bypasses provide the new value AFTER this cycle +; | | | A3-type bypasses provide the new value AFTER this cycle +; | | A1-type bypasses provide the new value AFTER this cycle +; | AGI resolution, actual USE of new value is DURING this cycle ; AGI detection (define_bypass 3 "z10_larl_A1, z10_la_fwd_A1, z10_other_fwd_A1, \ @@ -682,7 +681,6 @@ z10_cs, z10_stm, z10_other" "s390_agen_dep_p") - (define_bypass 5 "z10_larl_fwd_A3, z10_load_fwd_A3, z10_other_fwd_A3, \ z10_other_fr_A3, z10_int_fwd_A3, z10_int_fr_A3" "z10_agen, z10_la, z10_branch, z10_call, z10_load, \ @@ -699,6 +697,12 @@ z10_cs, z10_stm, z10_other" "s390_agen_dep_p") +(define_bypass 9 "z10_int_super, z10_int_fwd, z10_int_fr" + "z10_agen, z10_la, z10_branch, z10_call, z10_load, \ + z10_store, \ + z10_cs, z10_stm, z10_other" + "s390_agen_dep_p") + ; diff --git a/gcc/config/s390/fixdfdi.h b/gcc/config/s390/fixdfdi.h deleted file mode 100644 index ddddf3a7c9c..00000000000 --- a/gcc/config/s390/fixdfdi.h +++ /dev/null @@ -1,462 +0,0 @@ -/* Definitions of target machine for GNU compiler, for IBM S/390 - Copyright (C) 1999, 2000, 2001, 2007, 2008 Free Software Foundation, Inc. - Contributed by Hartmut Penner (hpenner@de.ibm.com) and - Ulrich Weigand (uweigand@de.ibm.com). - -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 3, 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 COPYING3. If not see -. */ - -#ifdef L_fixunstfdi - -#define EXPD(fp) (((fp.l.i[0]) >> 16) & 0x7FFF) -#define EXPONENT_BIAS 16383 -#define MANTISSA_BITS 112 -#define PRECISION (MANTISSA_BITS + 1) -#define SIGNBIT 0x80000000 -#define SIGND(fp) ((fp.l.i[0]) & SIGNBIT) -#define MANTD_HIGH_LL(fp) ((fp.ll[0] & HIGH_LL_FRAC_MASK) | HIGH_LL_UNIT_BIT) -#define MANTD_LOW_LL(fp) (fp.ll[1]) -#define FRACD_ZERO_P(fp) (!fp.ll[1] && !(fp.ll[0] & HIGH_LL_FRAC_MASK)) -#define HIGH_LL_FRAC_BITS 48 -#define HIGH_LL_UNIT_BIT ((UDItype_x)1 << HIGH_LL_FRAC_BITS) -#define HIGH_LL_FRAC_MASK (HIGH_LL_UNIT_BIT - 1) - -typedef int DItype_x __attribute__ ((mode (DI))); -typedef unsigned int UDItype_x __attribute__ ((mode (DI))); -typedef int SItype_x __attribute__ ((mode (SI))); -typedef unsigned int USItype_x __attribute__ ((mode (SI))); - -union double_long { - long double d; - struct { - SItype_x i[4]; /* 32 bit parts: 0 upper ... 3 lowest */ - } l; - UDItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */ -}; - -UDItype_x __fixunstfdi (long double a1); - -/* convert double to unsigned int */ -UDItype_x -__fixunstfdi (long double a1) -{ - register union double_long dl1; - register int exp; - register UDItype_x l; - - dl1.d = a1; - - /* +/- 0, denormalized, negative */ - if (!EXPD (dl1) || SIGND(dl1)) - return 0; - - /* The exponent - considered the binary point at the right end of - the mantissa. */ - exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS; - - /* number < 1: If the mantissa would need to be right-shifted more bits than - its size (plus the implied one bit on the left) the result would be - zero. */ - if (exp <= -PRECISION) - return 0; - - /* NaN: All exponent bits set and a nonzero fraction. */ - if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1)) - return 0x0ULL; - - /* One extra bit is needed for the unit bit which is appended by - MANTD_HIGH_LL on the left of the matissa. */ - exp += HIGH_LL_FRAC_BITS + 1; - - /* If the result would still need a left shift it will be too large - to be represented. */ - if (exp > 0) - return 0xFFFFFFFFFFFFFFFFULL; - - l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1) - | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1)); - - return l >> -exp; -} -#define __fixunstfdi ___fixunstfdi -#endif -#undef L_fixunstfdi - -#ifdef L_fixtfdi -#define EXPD(fp) (((fp.l.i[0]) >> 16) & 0x7FFF) -#define EXPONENT_BIAS 16383 -#define MANTISSA_BITS 112 -#define PRECISION (MANTISSA_BITS + 1) -#define SIGNBIT 0x80000000 -#define SIGND(fp) ((fp.l.i[0]) & SIGNBIT) -#define MANTD_HIGH_LL(fp) ((fp.ll[0] & HIGH_LL_FRAC_MASK) | HIGH_LL_UNIT_BIT) -#define MANTD_LOW_LL(fp) (fp.ll[1]) -#define FRACD_ZERO_P(fp) (!fp.ll[1] && !(fp.ll[0] & HIGH_LL_FRAC_MASK)) -#define HIGH_LL_FRAC_BITS 48 -#define HIGH_LL_UNIT_BIT ((UDItype_x)1 << HIGH_LL_FRAC_BITS) -#define HIGH_LL_FRAC_MASK (HIGH_LL_UNIT_BIT - 1) - -typedef int DItype_x __attribute__ ((mode (DI))); -typedef unsigned int UDItype_x __attribute__ ((mode (DI))); -typedef int SItype_x __attribute__ ((mode (SI))); -typedef unsigned int USItype_x __attribute__ ((mode (SI))); - -union double_long { - long double d; - struct { - SItype_x i[4]; /* 32 bit parts: 0 upper ... 3 lowest */ - } l; - UDItype_x ll[2]; /* 64 bit parts: 0 upper, 1 lower */ -}; - -DItype_x __fixtfdi (long double a1); - -/* convert double to unsigned int */ -DItype_x -__fixtfdi (long double a1) -{ - register union double_long dl1; - register int exp; - register UDItype_x l; - - dl1.d = a1; - - /* +/- 0, denormalized */ - if (!EXPD (dl1)) - return 0; - - /* The exponent - considered the binary point at the right end of - the mantissa. */ - exp = EXPD (dl1) - EXPONENT_BIAS - MANTISSA_BITS; - - /* number < 1: If the mantissa would need to be right-shifted more bits than - its size the result would be zero. */ - if (exp <= -PRECISION) - return 0; - - /* NaN: All exponent bits set and a nonzero fraction. */ - if ((EXPD(dl1) == 0x7fff) && !FRACD_ZERO_P (dl1)) - return 0x8000000000000000ULL; - - /* One extra bit is needed for the unit bit which is appended by - MANTD_HIGH_LL on the left of the matissa. */ - exp += HIGH_LL_FRAC_BITS + 1; - - /* If the result would still need a left shift it will be too large - to be represented. Compared to the unsigned variant we have to - take care that there is still space for the sign bit to be - applied. So we can only go on if there is a right-shift by one - or more. */ - if (exp >= 0) - { - l = 1ULL << 63; /* long long min */ - return SIGND (dl1) ? l : l - 1; - } - - l = MANTD_LOW_LL (dl1) >> (HIGH_LL_FRAC_BITS + 1) - | MANTD_HIGH_LL (dl1) << (64 - (HIGH_LL_FRAC_BITS + 1)); - - return SIGND (dl1) ? -(l >> -exp) : l >> -exp; -} -#define __fixtfdi ___fixtfdi -#endif -#undef L_fixtfdi - -#ifdef L_fixunsdfdi -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define EXCESSD 1022 -#define SIGNBIT 0x80000000 -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) -#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) -#define FRACD_LL(fp) (fp.ll & (HIDDEND_LL-1)) -#define HIDDEND_LL ((UDItype_x)1 << 52) - -typedef int DItype_x __attribute__ ((mode (DI))); -typedef unsigned int UDItype_x __attribute__ ((mode (DI))); -typedef int SItype_x __attribute__ ((mode (SI))); -typedef unsigned int USItype_x __attribute__ ((mode (SI))); - -union double_long { - double d; - struct { - SItype_x upper; - USItype_x lower; - } l; - UDItype_x ll; -}; - -UDItype_x __fixunsdfdi (double a1); - -/* convert double to unsigned int */ -UDItype_x -__fixunsdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register UDItype_x l; - - dl1.d = a1; - - /* +/- 0, denormalized, negative */ - - if (!EXPD (dl1) || SIGND(dl1)) - return 0; - - exp = EXPD (dl1) - EXCESSD - 53; - - /* number < 1 */ - - if (exp < -53) - return 0; - - /* NaN */ - - if ((EXPD(dl1) == 0x7ff) && (FRACD_LL(dl1) != 0)) /* NaN */ - return 0x0ULL; - - /* Number big number & + inf */ - - if (exp >= 12) { - return 0xFFFFFFFFFFFFFFFFULL; - } - - l = MANTD_LL(dl1); - - /* shift down until exp < 12 or l = 0 */ - if (exp > 0) - l <<= exp; - else - l >>= -exp; - - return l; -} -#define __fixunsdfdi ___fixunsdfdi -#endif -#undef L_fixunsdfdi - -#ifdef L_fixdfdi -#define EXPD(fp) (((fp.l.upper) >> 20) & 0x7FF) -#define EXCESSD 1022 -#define SIGNBIT 0x80000000 -#define SIGND(fp) ((fp.l.upper) & SIGNBIT) -#define MANTD_LL(fp) ((fp.ll & (HIDDEND_LL-1)) | HIDDEND_LL) -#define FRACD_LL(fp) (fp.ll & (HIDDEND_LL-1)) -#define HIDDEND_LL ((UDItype_x)1 << 52) - -typedef int DItype_x __attribute__ ((mode (DI))); -typedef unsigned int UDItype_x __attribute__ ((mode (DI))); -typedef int SItype_x __attribute__ ((mode (SI))); -typedef unsigned int USItype_x __attribute__ ((mode (SI))); - -union double_long { - double d; - struct { - SItype_x upper; - USItype_x lower; - } l; - UDItype_x ll; -}; - -DItype_x __fixdfdi (double a1); - -/* convert double to int */ -DItype_x -__fixdfdi (double a1) -{ - register union double_long dl1; - register int exp; - register DItype_x l; - - dl1.d = a1; - - /* +/- 0, denormalized */ - - if (!EXPD (dl1)) - return 0; - - exp = EXPD (dl1) - EXCESSD - 53; - - /* number < 1 */ - - if (exp < -53) - return 0; - - /* NaN */ - - if ((EXPD(dl1) == 0x7ff) && (FRACD_LL(dl1) != 0)) /* NaN */ - return 0x8000000000000000ULL; - - /* Number big number & +/- inf */ - - if (exp >= 11) { - l = (long long)1<<63; - if (!SIGND(dl1)) - l--; - return l; - } - - l = MANTD_LL(dl1); - - /* shift down until exp < 12 or l = 0 */ - if (exp > 0) - l <<= exp; - else - l >>= -exp; - - return (SIGND (dl1) ? -l : l); -} -#define __fixdfdi ___fixdfdi -#endif -#undef L_fixdfdi - -#ifdef L_fixunssfdi -#define EXP(fp) (((fp.l) >> 23) & 0xFF) -#define EXCESS 126 -#define SIGNBIT 0x80000000 -#define SIGN(fp) ((fp.l) & SIGNBIT) -#define HIDDEN (1 << 23) -#define MANT(fp) (((fp.l) & 0x7FFFFF) | HIDDEN) -#define FRAC(fp) ((fp.l) & 0x7FFFFF) - -typedef int DItype_x __attribute__ ((mode (DI))); -typedef unsigned int UDItype_x __attribute__ ((mode (DI))); -typedef int SItype_x __attribute__ ((mode (SI))); -typedef unsigned int USItype_x __attribute__ ((mode (SI))); - -union float_long - { - float f; - USItype_x l; - }; - -UDItype_x __fixunssfdi (float a1); - -/* convert float to unsigned int */ -UDItype_x -__fixunssfdi (float a1) -{ - register union float_long fl1; - register int exp; - register UDItype_x l; - - fl1.f = a1; - - /* +/- 0, denormalized, negative */ - - if (!EXP (fl1) || SIGN(fl1)) - return 0; - - exp = EXP (fl1) - EXCESS - 24; - - /* number < 1 */ - - if (exp < -24) - return 0; - - /* NaN */ - - if ((EXP(fl1) == 0xff) && (FRAC(fl1) != 0)) /* NaN */ - return 0x0ULL; - - /* Number big number & + inf */ - - if (exp >= 41) { - return 0xFFFFFFFFFFFFFFFFULL; - } - - l = MANT(fl1); - - if (exp > 0) - l <<= exp; - else - l >>= -exp; - - return l; -} -#define __fixunssfdi ___fixunssfdi -#endif -#undef L_fixunssfdi - -#ifdef L_fixsfdi -#define EXP(fp) (((fp.l) >> 23) & 0xFF) -#define EXCESS 126 -#define SIGNBIT 0x80000000 -#define SIGN(fp) ((fp.l) & SIGNBIT) -#define HIDDEN (1 << 23) -#define MANT(fp) (((fp.l) & 0x7FFFFF) | HIDDEN) -#define FRAC(fp) ((fp.l) & 0x7FFFFF) - -typedef int DItype_x __attribute__ ((mode (DI))); -typedef unsigned int UDItype_x __attribute__ ((mode (DI))); -typedef int SItype_x __attribute__ ((mode (SI))); -typedef unsigned int USItype_x __attribute__ ((mode (SI))); - -union float_long - { - float f; - USItype_x l; - }; - -DItype_x __fixsfdi (float a1); - -/* convert double to int */ -DItype_x -__fixsfdi (float a1) -{ - register union float_long fl1; - register int exp; - register DItype_x l; - - fl1.f = a1; - - /* +/- 0, denormalized */ - - if (!EXP (fl1)) - return 0; - - exp = EXP (fl1) - EXCESS - 24; - - /* number < 1 */ - - if (exp < -24) - return 0; - - /* NaN */ - - if ((EXP(fl1) == 0xff) && (FRAC(fl1) != 0)) /* NaN */ - return 0x8000000000000000ULL; - - /* Number big number & +/- inf */ - - if (exp >= 40) { - l = (long long)1<<63; - if (!SIGN(fl1)) - l--; - return l; - } - - l = MANT(fl1); - - if (exp > 0) - l <<= exp; - else - l >>= -exp; - - return (SIGN (fl1) ? -l : l); -} -#define __fixsfdi ___fixsfdi -#endif -#undef L_fixsfdi diff --git a/gcc/config/s390/libgcc-glibc.ver b/gcc/config/s390/libgcc-glibc.ver deleted file mode 100644 index 6fc52e40d78..00000000000 --- a/gcc/config/s390/libgcc-glibc.ver +++ /dev/null @@ -1,116 +0,0 @@ -# Copyright (C) 2002, 2006, 2008 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 3, 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 COPYING3. If not see -# . - -# In order to work around the very problems that force us to now generally -# create a libgcc.so, glibc reexported a number of routines from libgcc.a. -# By now choosing the same version tags for these specific routines, we -# maintain enough binary compatibility to allow future versions of glibc -# to defer implementation of these routines to libgcc.so via DT_AUXILIARY. - -# Note that we cannot use the default libgcc-glibc.ver file on s390x, -# because GLIBC_2.0 does not exist on this architecture, as the first -# ever glibc release on the platform was GLIBC_2.2. - -%ifndef __s390x__ -%exclude { - __divdi3 - __moddi3 - __udivdi3 - __umoddi3 - __register_frame - __register_frame_table - __deregister_frame - __register_frame_info - __deregister_frame_info - __frame_state_for - __register_frame_info_table -} - -%inherit GCC_3.0 GLIBC_2.0 -GLIBC_2.0 { - __divdi3 - __moddi3 - __udivdi3 - __umoddi3 - - __register_frame - __register_frame_table - __deregister_frame - __register_frame_info - __deregister_frame_info - __frame_state_for - __register_frame_info_table -} -%endif - -%ifdef __s390x__ -%exclude { - __register_frame - __register_frame_table - __deregister_frame - __register_frame_info - __deregister_frame_info - __frame_state_for - __register_frame_info_table -} - -%inherit GCC_3.0 GLIBC_2.2 -GLIBC_2.2 { - __register_frame - __register_frame_table - __deregister_frame - __register_frame_info - __deregister_frame_info - __frame_state_for - __register_frame_info_table -} -%endif - -# With GCC 4.1.0 long double 128 bit support was introduced. The -# following symbols coming from libgcc are enabled when -mlong-double-128 -# is specified. These lines make the symbols to get a @@GCC_4.1.0 attached. - -%exclude { - __divtc3 - __multc3 - __powitf2 - __fixtfti - __fixunstfti - __floattitf - - __fixtfdi - __fixunstfdi - __floatditf -} - -GCC_4.1.0 { - __divtc3 - __multc3 - __powitf2 - -%ifdef __s390x__ - __fixtfti - __fixunstfti - __floattitf - -%else - __fixtfdi - __fixunstfdi - __floatditf -%endif -} diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c index e439b01709f..a4334819203 100644 --- a/gcc/config/s390/s390.c +++ b/gcc/config/s390/s390.c @@ -9003,6 +9003,7 @@ s390_encode_section_info (tree decl, rtx rtl, int first) && GET_CODE (XEXP (rtl, 0)) == SYMBOL_REF && TREE_CONSTANT_POOL_ADDRESS_P (XEXP (rtl, 0)) && (MEM_ALIGN (rtl) == 0 + || GET_MODE_BITSIZE (GET_MODE (rtl)) == 0 || MEM_ALIGN (rtl) < GET_MODE_BITSIZE (GET_MODE (rtl)))) SYMBOL_REF_FLAGS (XEXP (rtl, 0)) |= SYMBOL_FLAG_NOT_NATURALLY_ALIGNED; } @@ -9863,9 +9864,12 @@ s390_z10_optimize_cmp (rtx insn) if (!REG_P (*op0) || !REG_P (*op1)) return false; + if (GET_MODE_CLASS (GET_MODE (*op0)) != MODE_INT) + return false; + /* Swap the COMPARE arguments and its mask if there is a conflicting access in the previous insn. */ - prev_insn = PREV_INSN (insn); + prev_insn = prev_active_insn (insn); if (prev_insn != NULL_RTX && INSN_P (prev_insn) && reg_referenced_p (*op1, PATTERN (prev_insn))) s390_swap_cmp (cond, op0, op1, insn); @@ -9876,7 +9880,7 @@ s390_z10_optimize_cmp (rtx insn) the operands, or if swapping them would cause a conflict with the previous insn, issue a NOP after the COMPARE in order to separate the two instuctions. */ - next_insn = NEXT_INSN (insn); + next_insn = next_active_insn (insn); if (next_insn != NULL_RTX && INSN_P (next_insn) && s390_non_addr_reg_read_p (*op1, next_insn)) { diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index ffb96cd0f34..2da8b8753e2 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -24,12 +24,6 @@ along with GCC; see the file COPYING3. If not see #ifndef _S390_H #define _S390_H -/* Override the __fixdfdi etc. routines when building libgcc2. - ??? This should be done in a cleaner way ... */ -#if defined (IN_LIBGCC2) && !defined (__s390x__) -#include -#endif - /* Which processor to generate code or schedule for. The cpu attribute defines a list that mirrors this list, so changes to s390.md must be made at the same time. */ diff --git a/gcc/config/s390/s390.md b/gcc/config/s390/s390.md index db326ee766c..8f4a71feb3f 100644 --- a/gcc/config/s390/s390.md +++ b/gcc/config/s390/s390.md @@ -220,7 +220,7 @@ ;; reg: Instruction does not use the agen unit (define_attr "atype" "agen,reg" - (if_then_else (eq_attr "op_type" "E,RR,RI,RRE") + (if_then_else (eq_attr "op_type" "E,RR,RI,RRE,RSI,RIL,RIE,RRF,RRR") (const_string "reg") (const_string "agen"))) @@ -8941,18 +8941,16 @@ ; (define_insn "prefetch" - [(prefetch (match_operand 0 "address_operand" "ZQZS,ZRZT,X") - (match_operand:SI 1 "const_int_operand" " n, n,n") - (match_operand:SI 2 "const_int_operand" " n, n,n"))] - "TARGET_ZARCH && s390_tune == PROCESSOR_2097_Z10" + [(prefetch (match_operand 0 "address_operand" "ZQZRZSZT,X") + (match_operand:SI 1 "const_int_operand" " n,n") + (match_operand:SI 2 "const_int_operand" " n,n"))] + "TARGET_Z10" { switch (which_alternative) { case 0: - return INTVAL (operands[1]) == 1 ? "stcmh\t2,0,%a0" : "stcmh\t1,0,%a0"; - case 1: return INTVAL (operands[1]) == 1 ? "pfd\t2,%a0" : "pfd\t1,%a0"; - case 2: + case 1: if (larl_operand (operands[0], Pmode)) return INTVAL (operands[1]) == 1 ? "pfdrl\t2,%a0" : "pfdrl\t1,%a0"; default: @@ -8963,10 +8961,9 @@ return ""; } } - [(set_attr "type" "store,load,larl") - (set_attr "op_type" "RSY,RXY,RIL") - (set_attr "z10prop" "z10_super") - (set_attr "cpu_facility" "*,z10,z10")]) + [(set_attr "type" "load,larl") + (set_attr "op_type" "RXY,RIL") + (set_attr "z10prop" "z10_super")]) ; diff --git a/gcc/config/s390/t-crtstuff b/gcc/config/s390/t-crtstuff deleted file mode 100644 index 39b0eba6b97..00000000000 --- a/gcc/config/s390/t-crtstuff +++ /dev/null @@ -1,5 +0,0 @@ -# crtend*.o cannot be compiled without -fno-asynchronous-unwind-tables, -# because then __FRAME_END__ might not be the last thing in .eh_frame -# section. -CRTSTUFF_T_CFLAGS = -fno-asynchronous-unwind-tables -TARGET_LIBGCC2_CFLAGS += -mlong-double-128 diff --git a/gcc/config/s390/t-linux b/gcc/config/s390/t-linux deleted file mode 100644 index d5a92781450..00000000000 --- a/gcc/config/s390/t-linux +++ /dev/null @@ -1,3 +0,0 @@ -# Override t-slibgcc-elf-ver to export some libgcc symbols with -# the symbol versions that glibc used. -SHLIB_MAPFILES = $(srcdir)/libgcc-std.ver $(srcdir)/config/s390/libgcc-glibc.ver diff --git a/gcc/config/s390/t-linux64 b/gcc/config/s390/t-linux64 index 0ffb6902c18..36aced09c2c 100644 --- a/gcc/config/s390/t-linux64 +++ b/gcc/config/s390/t-linux64 @@ -1,8 +1,3 @@ MULTILIB_OPTIONS = m64/m31 MULTILIB_DIRNAMES = 64 32 MULTILIB_OSDIRNAMES = ../lib64 ../lib - -LIBGCC = stmp-multilib -INSTALL_LIBGCC = install-multilib - -EXTRA_MULTILIB_PARTS=crtbegin.o crtend.o crtbeginS.o crtendS.o crtbeginT.o diff --git a/gcc/config/s390/t-tpf b/gcc/config/s390/t-tpf deleted file mode 100644 index 6e4c377697c..00000000000 --- a/gcc/config/s390/t-tpf +++ /dev/null @@ -1,9 +0,0 @@ -# Compile crtbeginS.o and crtendS.o with pic. -CRTSTUFF_T_CFLAGS_S = $(CRTSTUFF_T_CFLAGS) -fPIC -# Compile libgcc2.a with pic. -TARGET_LIBGCC2_CFLAGS = -fPIC - -# Use unwind-dw2-fde-glibc. -LIB2ADDEH = $(srcdir)/unwind-dw2.c $(srcdir)/unwind-dw2-fde-glibc.c \ - $(srcdir)/unwind-sjlj.c $(srcdir)/gthr-gnat.c $(srcdir)/unwind-c.c -LIB2ADDEHDEP = unwind.inc unwind-dw2-fde.h diff --git a/gcc/config/s390/tpf.h b/gcc/config/s390/tpf.h index 5ffbd07f309..455c8ad92bc 100644 --- a/gcc/config/s390/tpf.h +++ b/gcc/config/s390/tpf.h @@ -55,7 +55,7 @@ along with GCC; see the file COPYING3. If not see enable TPF profiling support and the standard backchain by default. */ #undef TARGET_DEFAULT #define TARGET_DEFAULT (MASK_TPF_PROFILING | MASK_64BIT | MASK_ZARCH \ - | MASK_HARD_FLOAT | MASK_BACKCHAIN) + | MASK_HARD_DFP | MASK_BACKCHAIN) /* Exception handling. */ diff --git a/gcc/config/score/score.h b/gcc/config/score/score.h index 0b7af7b2739..cde9c222546 100644 --- a/gcc/config/score/score.h +++ b/gcc/config/score/score.h @@ -688,9 +688,6 @@ typedef struct score_args #define HAVE_PRE_MODIFY_REG 0 #define HAVE_POST_MODIFY_REG 0 -/* Recognize any constant value that is a valid address. */ -#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) - /* Maximum number of registers that can appear in a valid memory address. */ #define MAX_REGS_PER_ADDRESS 1 diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 679cf11e83e..26bceea670d 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -222,7 +222,9 @@ static bool sh_optimize_target_register_callee_saved (bool); static bool sh_ms_bitfield_layout_p (const_tree); static void sh_init_builtins (void); +static tree sh_builtin_decl (unsigned, bool); static void sh_media_init_builtins (void); +static tree sh_media_builtin_decl (unsigned, bool); static rtx sh_expand_builtin (tree, rtx, rtx, enum machine_mode, int); static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static void sh_file_start (void); @@ -416,6 +418,8 @@ static const struct attribute_spec sh_attribute_table[] = #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS sh_init_builtins +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL sh_builtin_decl #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN sh_expand_builtin @@ -9427,6 +9431,7 @@ nonpic_symbol_mentioned_p (rtx x) || XINT (x, 1) == UNSPEC_GOTPLT || XINT (x, 1) == UNSPEC_GOTTPOFF || XINT (x, 1) == UNSPEC_DTPOFF + || XINT (x, 1) == UNSPEC_TPOFF || XINT (x, 1) == UNSPEC_PLT || XINT (x, 1) == UNSPEC_SYMOFF || XINT (x, 1) == UNSPEC_PCREL_SYMOFF)) @@ -10520,6 +10525,7 @@ struct builtin_description const enum insn_code icode; const char *const name; int signature; + tree fndecl; }; /* describe number and signedness of arguments; arg[0] == result @@ -10586,99 +10592,99 @@ static const char signature_args[][4] = /* mshalds, mshard, mshards, mshlld, mshlrd: shift count is unsigned int. */ /* mshards_q: returns signed short. */ /* nsb: takes long long arg, returns unsigned char. */ -static const struct builtin_description bdesc[] = -{ - { CODE_FOR_absv2si2, "__builtin_absv2si2", SH_BLTIN_V2SI2 }, - { CODE_FOR_absv4hi2, "__builtin_absv4hi2", SH_BLTIN_V4HI2 }, - { CODE_FOR_addv2si3, "__builtin_addv2si3", SH_BLTIN_V2SI3 }, - { CODE_FOR_addv4hi3, "__builtin_addv4hi3", SH_BLTIN_V4HI3 }, - { CODE_FOR_ssaddv2si3,"__builtin_ssaddv2si3", SH_BLTIN_V2SI3 }, - { CODE_FOR_usaddv8qi3,"__builtin_usaddv8qi3", SH_BLTIN_V8QI3 }, - { CODE_FOR_ssaddv4hi3,"__builtin_ssaddv4hi3", SH_BLTIN_V4HI3 }, - { CODE_FOR_alloco_i, "__builtin_sh_media_ALLOCO", SH_BLTIN_PV }, - { CODE_FOR_negcmpeqv8qi,"__builtin_sh_media_MCMPEQ_B", SH_BLTIN_V8QI3 }, - { CODE_FOR_negcmpeqv2si,"__builtin_sh_media_MCMPEQ_L", SH_BLTIN_V2SI3 }, - { CODE_FOR_negcmpeqv4hi,"__builtin_sh_media_MCMPEQ_W", SH_BLTIN_V4HI3 }, - { CODE_FOR_negcmpgtuv8qi,"__builtin_sh_media_MCMPGT_UB", SH_BLTIN_V8QI3 }, - { CODE_FOR_negcmpgtv2si,"__builtin_sh_media_MCMPGT_L", SH_BLTIN_V2SI3 }, - { CODE_FOR_negcmpgtv4hi,"__builtin_sh_media_MCMPGT_W", SH_BLTIN_V4HI3 }, - { CODE_FOR_mcmv, "__builtin_sh_media_MCMV", SH_BLTIN_UUUU }, - { CODE_FOR_mcnvs_lw, "__builtin_sh_media_MCNVS_LW", SH_BLTIN_3 }, - { CODE_FOR_mcnvs_wb, "__builtin_sh_media_MCNVS_WB", SH_BLTIN_V4HI2V8QI }, - { CODE_FOR_mcnvs_wub, "__builtin_sh_media_MCNVS_WUB", SH_BLTIN_V4HI2V8QI }, - { CODE_FOR_mextr1, "__builtin_sh_media_MEXTR1", SH_BLTIN_V8QI3 }, - { CODE_FOR_mextr2, "__builtin_sh_media_MEXTR2", SH_BLTIN_V8QI3 }, - { CODE_FOR_mextr3, "__builtin_sh_media_MEXTR3", SH_BLTIN_V8QI3 }, - { CODE_FOR_mextr4, "__builtin_sh_media_MEXTR4", SH_BLTIN_V8QI3 }, - { CODE_FOR_mextr5, "__builtin_sh_media_MEXTR5", SH_BLTIN_V8QI3 }, - { CODE_FOR_mextr6, "__builtin_sh_media_MEXTR6", SH_BLTIN_V8QI3 }, - { CODE_FOR_mextr7, "__builtin_sh_media_MEXTR7", SH_BLTIN_V8QI3 }, - { CODE_FOR_mmacfx_wl, "__builtin_sh_media_MMACFX_WL", SH_BLTIN_MAC_HISI }, - { CODE_FOR_mmacnfx_wl,"__builtin_sh_media_MMACNFX_WL", SH_BLTIN_MAC_HISI }, - { CODE_FOR_mulv2si3, "__builtin_mulv2si3", SH_BLTIN_V2SI3, }, - { CODE_FOR_mulv4hi3, "__builtin_mulv4hi3", SH_BLTIN_V4HI3 }, - { CODE_FOR_mmulfx_l, "__builtin_sh_media_MMULFX_L", SH_BLTIN_V2SI3 }, - { CODE_FOR_mmulfx_w, "__builtin_sh_media_MMULFX_W", SH_BLTIN_V4HI3 }, - { CODE_FOR_mmulfxrp_w,"__builtin_sh_media_MMULFXRP_W", SH_BLTIN_V4HI3 }, - { CODE_FOR_mmulhi_wl, "__builtin_sh_media_MMULHI_WL", SH_BLTIN_V4HI2V2SI }, - { CODE_FOR_mmullo_wl, "__builtin_sh_media_MMULLO_WL", SH_BLTIN_V4HI2V2SI }, - { CODE_FOR_mmulsum_wq,"__builtin_sh_media_MMULSUM_WQ", SH_BLTIN_XXUU }, - { CODE_FOR_mperm_w, "__builtin_sh_media_MPERM_W", SH_BLTIN_SH_HI }, - { CODE_FOR_msad_ubq, "__builtin_sh_media_MSAD_UBQ", SH_BLTIN_XXUU }, - { CODE_FOR_mshalds_l, "__builtin_sh_media_MSHALDS_L", SH_BLTIN_SH_SI }, - { CODE_FOR_mshalds_w, "__builtin_sh_media_MSHALDS_W", SH_BLTIN_SH_HI }, - { CODE_FOR_ashrv2si3, "__builtin_ashrv2si3", SH_BLTIN_SH_SI }, - { CODE_FOR_ashrv4hi3, "__builtin_ashrv4hi3", SH_BLTIN_SH_HI }, - { CODE_FOR_mshards_q, "__builtin_sh_media_MSHARDS_Q", SH_BLTIN_SUS }, - { CODE_FOR_mshfhi_b, "__builtin_sh_media_MSHFHI_B", SH_BLTIN_V8QI3 }, - { CODE_FOR_mshfhi_l, "__builtin_sh_media_MSHFHI_L", SH_BLTIN_V2SI3 }, - { CODE_FOR_mshfhi_w, "__builtin_sh_media_MSHFHI_W", SH_BLTIN_V4HI3 }, - { CODE_FOR_mshflo_b, "__builtin_sh_media_MSHFLO_B", SH_BLTIN_V8QI3 }, - { CODE_FOR_mshflo_l, "__builtin_sh_media_MSHFLO_L", SH_BLTIN_V2SI3 }, - { CODE_FOR_mshflo_w, "__builtin_sh_media_MSHFLO_W", SH_BLTIN_V4HI3 }, - { CODE_FOR_ashlv2si3, "__builtin_ashlv2si3", SH_BLTIN_SH_SI }, - { CODE_FOR_ashlv4hi3, "__builtin_ashlv4hi3", SH_BLTIN_SH_HI }, - { CODE_FOR_lshrv2si3, "__builtin_lshrv2si3", SH_BLTIN_SH_SI }, - { CODE_FOR_lshrv4hi3, "__builtin_lshrv4hi3", SH_BLTIN_SH_HI }, - { CODE_FOR_subv2si3, "__builtin_subv2si3", SH_BLTIN_V2SI3 }, - { CODE_FOR_subv4hi3, "__builtin_subv4hi3", SH_BLTIN_V4HI3 }, - { CODE_FOR_sssubv2si3,"__builtin_sssubv2si3", SH_BLTIN_V2SI3 }, - { CODE_FOR_ussubv8qi3,"__builtin_ussubv8qi3", SH_BLTIN_V8QI3 }, - { CODE_FOR_sssubv4hi3,"__builtin_sssubv4hi3", SH_BLTIN_V4HI3 }, - { CODE_FOR_fcosa_s, "__builtin_sh_media_FCOSA_S", SH_BLTIN_SISF }, - { CODE_FOR_fsina_s, "__builtin_sh_media_FSINA_S", SH_BLTIN_SISF }, - { CODE_FOR_fipr, "__builtin_sh_media_FIPR_S", SH_BLTIN_3 }, - { CODE_FOR_ftrv, "__builtin_sh_media_FTRV_S", SH_BLTIN_3 }, - { CODE_FOR_mac_media, "__builtin_sh_media_FMAC_S", SH_BLTIN_3 }, - { CODE_FOR_sqrtdf2, "__builtin_sh_media_FSQRT_D", SH_BLTIN_2 }, - { CODE_FOR_sqrtsf2, "__builtin_sh_media_FSQRT_S", SH_BLTIN_2 }, - { CODE_FOR_fsrra_s, "__builtin_sh_media_FSRRA_S", SH_BLTIN_2 }, - { CODE_FOR_ldhi_l, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L }, - { CODE_FOR_ldhi_q, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q }, - { CODE_FOR_ldlo_l, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L }, - { CODE_FOR_ldlo_q, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q }, - { CODE_FOR_sthi_l, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L }, - { CODE_FOR_sthi_q, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q }, - { CODE_FOR_stlo_l, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L }, - { CODE_FOR_stlo_q, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q }, - { CODE_FOR_ldhi_l64, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L64 }, - { CODE_FOR_ldhi_q64, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q64 }, - { CODE_FOR_ldlo_l64, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L64 }, - { CODE_FOR_ldlo_q64, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q64 }, - { CODE_FOR_sthi_l64, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L64 }, - { CODE_FOR_sthi_q64, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q64 }, - { CODE_FOR_stlo_l64, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L64 }, - { CODE_FOR_stlo_q64, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q64 }, - { CODE_FOR_nsb, "__builtin_sh_media_NSB", SH_BLTIN_SU }, - { CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2 }, - { CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV }, +static struct builtin_description bdesc[] = +{ + { CODE_FOR_absv2si2, "__builtin_absv2si2", SH_BLTIN_V2SI2, 0 }, + { CODE_FOR_absv4hi2, "__builtin_absv4hi2", SH_BLTIN_V4HI2, 0 }, + { CODE_FOR_addv2si3, "__builtin_addv2si3", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_addv4hi3, "__builtin_addv4hi3", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_ssaddv2si3,"__builtin_ssaddv2si3", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_usaddv8qi3,"__builtin_usaddv8qi3", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_ssaddv4hi3,"__builtin_ssaddv4hi3", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_alloco_i, "__builtin_sh_media_ALLOCO", SH_BLTIN_PV, 0 }, + { CODE_FOR_negcmpeqv8qi,"__builtin_sh_media_MCMPEQ_B", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_negcmpeqv2si,"__builtin_sh_media_MCMPEQ_L", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_negcmpeqv4hi,"__builtin_sh_media_MCMPEQ_W", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_negcmpgtuv8qi,"__builtin_sh_media_MCMPGT_UB", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_negcmpgtv2si,"__builtin_sh_media_MCMPGT_L", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_negcmpgtv4hi,"__builtin_sh_media_MCMPGT_W", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_mcmv, "__builtin_sh_media_MCMV", SH_BLTIN_UUUU, 0 }, + { CODE_FOR_mcnvs_lw, "__builtin_sh_media_MCNVS_LW", SH_BLTIN_3, 0 }, + { CODE_FOR_mcnvs_wb, "__builtin_sh_media_MCNVS_WB", SH_BLTIN_V4HI2V8QI, 0 }, + { CODE_FOR_mcnvs_wub, "__builtin_sh_media_MCNVS_WUB", SH_BLTIN_V4HI2V8QI, 0 }, + { CODE_FOR_mextr1, "__builtin_sh_media_MEXTR1", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mextr2, "__builtin_sh_media_MEXTR2", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mextr3, "__builtin_sh_media_MEXTR3", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mextr4, "__builtin_sh_media_MEXTR4", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mextr5, "__builtin_sh_media_MEXTR5", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mextr6, "__builtin_sh_media_MEXTR6", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mextr7, "__builtin_sh_media_MEXTR7", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mmacfx_wl, "__builtin_sh_media_MMACFX_WL", SH_BLTIN_MAC_HISI, 0 }, + { CODE_FOR_mmacnfx_wl,"__builtin_sh_media_MMACNFX_WL", SH_BLTIN_MAC_HISI, 0 }, + { CODE_FOR_mulv2si3, "__builtin_mulv2si3", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_mulv4hi3, "__builtin_mulv4hi3", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_mmulfx_l, "__builtin_sh_media_MMULFX_L", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_mmulfx_w, "__builtin_sh_media_MMULFX_W", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_mmulfxrp_w,"__builtin_sh_media_MMULFXRP_W", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_mmulhi_wl, "__builtin_sh_media_MMULHI_WL", SH_BLTIN_V4HI2V2SI, 0 }, + { CODE_FOR_mmullo_wl, "__builtin_sh_media_MMULLO_WL", SH_BLTIN_V4HI2V2SI, 0 }, + { CODE_FOR_mmulsum_wq,"__builtin_sh_media_MMULSUM_WQ", SH_BLTIN_XXUU, 0 }, + { CODE_FOR_mperm_w, "__builtin_sh_media_MPERM_W", SH_BLTIN_SH_HI, 0 }, + { CODE_FOR_msad_ubq, "__builtin_sh_media_MSAD_UBQ", SH_BLTIN_XXUU, 0 }, + { CODE_FOR_mshalds_l, "__builtin_sh_media_MSHALDS_L", SH_BLTIN_SH_SI, 0 }, + { CODE_FOR_mshalds_w, "__builtin_sh_media_MSHALDS_W", SH_BLTIN_SH_HI, 0 }, + { CODE_FOR_ashrv2si3, "__builtin_ashrv2si3", SH_BLTIN_SH_SI, 0 }, + { CODE_FOR_ashrv4hi3, "__builtin_ashrv4hi3", SH_BLTIN_SH_HI, 0 }, + { CODE_FOR_mshards_q, "__builtin_sh_media_MSHARDS_Q", SH_BLTIN_SUS, 0 }, + { CODE_FOR_mshfhi_b, "__builtin_sh_media_MSHFHI_B", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mshfhi_l, "__builtin_sh_media_MSHFHI_L", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_mshfhi_w, "__builtin_sh_media_MSHFHI_W", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_mshflo_b, "__builtin_sh_media_MSHFLO_B", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_mshflo_l, "__builtin_sh_media_MSHFLO_L", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_mshflo_w, "__builtin_sh_media_MSHFLO_W", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_ashlv2si3, "__builtin_ashlv2si3", SH_BLTIN_SH_SI, 0 }, + { CODE_FOR_ashlv4hi3, "__builtin_ashlv4hi3", SH_BLTIN_SH_HI, 0 }, + { CODE_FOR_lshrv2si3, "__builtin_lshrv2si3", SH_BLTIN_SH_SI, 0 }, + { CODE_FOR_lshrv4hi3, "__builtin_lshrv4hi3", SH_BLTIN_SH_HI, 0 }, + { CODE_FOR_subv2si3, "__builtin_subv2si3", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_subv4hi3, "__builtin_subv4hi3", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_sssubv2si3,"__builtin_sssubv2si3", SH_BLTIN_V2SI3, 0 }, + { CODE_FOR_ussubv8qi3,"__builtin_ussubv8qi3", SH_BLTIN_V8QI3, 0 }, + { CODE_FOR_sssubv4hi3,"__builtin_sssubv4hi3", SH_BLTIN_V4HI3, 0 }, + { CODE_FOR_fcosa_s, "__builtin_sh_media_FCOSA_S", SH_BLTIN_SISF, 0 }, + { CODE_FOR_fsina_s, "__builtin_sh_media_FSINA_S", SH_BLTIN_SISF, 0 }, + { CODE_FOR_fipr, "__builtin_sh_media_FIPR_S", SH_BLTIN_3, 0 }, + { CODE_FOR_ftrv, "__builtin_sh_media_FTRV_S", SH_BLTIN_3, 0 }, + { CODE_FOR_mac_media, "__builtin_sh_media_FMAC_S", SH_BLTIN_3, 0 }, + { CODE_FOR_sqrtdf2, "__builtin_sh_media_FSQRT_D", SH_BLTIN_2, 0 }, + { CODE_FOR_sqrtsf2, "__builtin_sh_media_FSQRT_S", SH_BLTIN_2, 0 }, + { CODE_FOR_fsrra_s, "__builtin_sh_media_FSRRA_S", SH_BLTIN_2, 0 }, + { CODE_FOR_ldhi_l, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L, 0 }, + { CODE_FOR_ldhi_q, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q, 0 }, + { CODE_FOR_ldlo_l, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L, 0 }, + { CODE_FOR_ldlo_q, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q, 0 }, + { CODE_FOR_sthi_l, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L, 0 }, + { CODE_FOR_sthi_q, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q, 0 }, + { CODE_FOR_stlo_l, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L, 0 }, + { CODE_FOR_stlo_q, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q, 0 }, + { CODE_FOR_ldhi_l64, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L64, 0 }, + { CODE_FOR_ldhi_q64, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q64, 0 }, + { CODE_FOR_ldlo_l64, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L64, 0 }, + { CODE_FOR_ldlo_q64, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q64, 0 }, + { CODE_FOR_sthi_l64, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L64, 0 }, + { CODE_FOR_sthi_q64, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q64, 0 }, + { CODE_FOR_stlo_l64, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L64, 0 }, + { CODE_FOR_stlo_q64, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q64, 0 }, + { CODE_FOR_nsb, "__builtin_sh_media_NSB", SH_BLTIN_SU, 0 }, + { CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 }, + { CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV, 0 }, }; static void sh_media_init_builtins (void) { tree shared[SH_BLTIN_NUM_SHARED_SIGNATURES]; - const struct builtin_description *d; + struct builtin_description *d; memset (shared, 0, sizeof shared); for (d = bdesc; d - bdesc < (int) ARRAY_SIZE (bdesc); d++) @@ -10724,11 +10730,23 @@ sh_media_init_builtins (void) if (signature < SH_BLTIN_NUM_SHARED_SIGNATURES) shared[signature] = type; } - add_builtin_function (d->name, type, d - bdesc, BUILT_IN_MD, - NULL, NULL_TREE); + d->fndecl = + add_builtin_function (d->name, type, d - bdesc, BUILT_IN_MD, + NULL, NULL_TREE); } } +/* Returns the shmedia builtin decl for CODE. */ + +static tree +sh_media_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= ARRAY_SIZE (bdesc)) + return error_mark_node; + + return bdesc[code].fndecl; +} + /* Implements target hook vector_mode_supported_p. */ bool sh_vector_mode_supported_p (enum machine_mode mode) @@ -10767,6 +10785,17 @@ sh_init_builtins (void) sh_media_init_builtins (); } +/* Returns the sh builtin decl for CODE. */ + +static tree +sh_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (TARGET_SHMEDIA) + return sh_media_builtin_decl (code, initialize_p); + + return error_mark_node; +} + /* Expand an expression EXP that calls a built-in function, with result going to TARGET if that's convenient (and in mode MODE if that's convenient). diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index f06098bfc1b..7fa634777b3 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -6824,8 +6824,8 @@ label: ;; jump around the unconditional jump because it was out of range. (define_insn "stuff_delay_slot" [(set (pc) - (unspec [(match_operand:SI 0 "const_int_operand" "") (pc)] UNSPEC_BBR)) - (set (reg:SI T_REG) (match_operand:SI 1 "const_int_operand" ""))] + (unspec [(match_operand:SI 0 "const_int_operand" "") (pc) + (match_operand:SI 1 "const_int_operand" "")] UNSPEC_BBR))] "TARGET_SH1" "" [(set_attr "length" "0") @@ -6889,8 +6889,6 @@ label: "TARGET_SHMEDIA" " { - /* hack to generate same code. */ - rtx tmp_di = GET_CODE (operands[0]) == UNORDERED ? NULL : gen_reg_rtx (DImode); rtx tmp = gen_reg_rtx (SImode); rtx cmp; if (GET_CODE (operands[0]) == NE) @@ -6900,13 +6898,12 @@ label: operands[1], operands[2]); emit_insn (gen_cstore4_media (tmp, cmp, operands[1], operands[2])); - if (tmp_di) emit_insn (gen_extendsidi2 (tmp_di, tmp)); else tmp_di = tmp; if (GET_CODE (cmp) == GET_CODE (operands[0])) - operands[0] = gen_rtx_NE (VOIDmode, tmp_di, const0_rtx); + operands[0] = gen_rtx_NE (VOIDmode, tmp, const0_rtx); else - operands[0] = gen_rtx_EQ (VOIDmode, tmp_di, const0_rtx); - operands[1] = tmp_di; + operands[0] = gen_rtx_EQ (VOIDmode, tmp, const0_rtx); + operands[1] = tmp; operands[2] = const0_rtx; operands[3] = gen_rtx_LABEL_REF (Pmode, operands[3]); }") diff --git a/gcc/config/sparc/sol2-unwind.h b/gcc/config/sparc/sol2-unwind.h new file mode 100644 index 00000000000..c98dc4dc088 --- /dev/null +++ b/gcc/config/sparc/sol2-unwind.h @@ -0,0 +1,458 @@ +/* DWARF2 EH unwinding support for SPARC Solaris. + Copyright (C) 2009 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 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +/* Do code reading to identify a signal frame, and set the frame + state data appropriately. See unwind-dw2.c for the structs. */ + +#include + +#if defined(__arch64__) + +#define MD_FALLBACK_FRAME_STATE_FOR sparc64_fallback_frame_state + +static _Unwind_Reason_Code +sparc64_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + void *pc = context->ra; + void *this_cfa = context->cfa; + void *new_cfa, *ra_location, *shifted_ra_location; + int regs_off; + int fpu_save_off; + unsigned char fpu_save; + int i; + + /* This is the observed pattern for the sigacthandler in Solaris 8. */ + unsigned int sigacthandler_sol8_pattern [] + = {0x9401400f, 0xca5aafa0, 0x913e2000, 0x892a3003, + 0xe0590005, 0x9fc40000, 0x9410001a, 0x80a6e008}; + + /* This is the observed pattern for the sigacthandler in Solaris 9. */ + unsigned int sigacthandler_sol9_pattern [] + = {0xa33e2000, 0x00000000, 0x892c7003, 0x90100011, + 0xe0590005, 0x9fc40000, 0x9410001a, 0x80a46008}; + + /* This is the observed pattern for the __sighndlr. */ + unsigned int sighndlr_pattern [] + = {0x9de3bf50, 0x90100018, 0x92100019, 0x9fc6c000, + 0x9410001a, 0x81c7e008, 0x81e80000}; + + /* Deal with frame-less function from which a signal was raised. */ + if (_Unwind_IsSignalFrame (context)) + { + /* The CFA is by definition unmodified in this case. */ + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = __builtin_dwarf_sp_column (); + fs->regs.cfa_offset = 0; + + /* This is the canonical RA column. */ + fs->retaddr_column = 15; + + return _URC_NO_REASON; + } + + /* Look for the sigacthandler pattern. The pattern changes slightly + in different versions of the operating system, so we skip the + comparison against pc-(4*6) for Solaris 9. */ + if (( *(unsigned int *)(pc-(4*7)) == sigacthandler_sol8_pattern[0] + && *(unsigned int *)(pc-(4*6)) == sigacthandler_sol8_pattern[1] + && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol8_pattern[2] + && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol8_pattern[3] + && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol8_pattern[4] + && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol8_pattern[5] + && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol8_pattern[6] + && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol8_pattern[7] ) || + ( *(unsigned int *)(pc-(4*7)) == sigacthandler_sol9_pattern[0] + /* skip pc-(4*6) */ + && *(unsigned int *)(pc-(4*5)) == sigacthandler_sol9_pattern[2] + && *(unsigned int *)(pc-(4*4)) == sigacthandler_sol9_pattern[3] + && *(unsigned int *)(pc-(4*3)) == sigacthandler_sol9_pattern[4] + && *(unsigned int *)(pc-(4*2)) == sigacthandler_sol9_pattern[5] + && *(unsigned int *)(pc-(4*1)) == sigacthandler_sol9_pattern[6] + && *(unsigned int *)(pc-(4*0)) == sigacthandler_sol9_pattern[7] ) ) + /* We need to move up two frames (the kernel frame and the handler + frame). Minimum stack frame size is 176 bytes (128 + 48): 128 + bytes for spilling register window (16 extended words for in + and local registers), and 6 extended words to store at least + 6 arguments to callees, The kernel frame and the sigacthandler + both have this minimal stack. The ucontext_t structure is after + this offset. */ + regs_off = 176 + 176; + + /* Look for the __sighndlr pattern. */ + else if ( *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0] + && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1] + && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2] + && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3] + && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4] + && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5] + && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] ) + { + /* We have observed different calling frames among different + versions of the operating system, so that we need to + discriminate using the upper frame. We look for the return + address of the caller frame (there is an offset of 15 double + words between the frame address and the place where this return + address is stored) in order to do some more pattern matching. */ + unsigned int cuh_pattern + = *(unsigned int *)(*(unsigned long *)(this_cfa + 15*8) - 4); + + if (cuh_pattern == 0x9410001a || cuh_pattern == 0x94100013) + /* This matches the call_user_handler pattern for Solaris 9 and + for Solaris 8 running inside Solaris Containers respectively. + We need to move up four frames (the kernel frame, the signal + frame, the call_user_handler frame, the __sighndlr frame). + Three of them have the minimum stack frame size (kernel, + signal, and __sighndlr frames) of 176 bytes, and there is + another with a stack frame of 304 bytes (the call_user_handler + frame). The ucontext_t structure is after this offset. */ + regs_off = 176 + 176 + 176 + 304; + else + /* We need to move up three frames (the kernel frame, the + sigacthandler frame, and the __sighndlr frame). The kernel + frame has a stack frame size of 176, the __sighndlr frames of + 304 bytes, and there is a stack frame of 176 bytes for the + sigacthandler frame. The ucontext_t structure is after this + offset. */ + regs_off = 176 + 304 + 176; + } + + /* Exit if the pattern at the return address does not match the + previous three patterns. */ + else + return _URC_END_OF_STACK; + + /* FPU information can be extracted from the ucontext_t structure + that is the third argument for the signal handler, that is saved + in the stack. There are 64 bytes between the beginning of the + ucontext_t argument of the signal handler and the uc_mcontext + field. There are 176 bytes between the beginning of uc_mcontext + and the beginning of the fpregs field. */ + fpu_save_off = regs_off + (8*10) + 176; + + /* The fpregs field contains 32 extended words at the beginning that + contain the fpu state. Then there are 2 extended words and two + bytes. */ + fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (8*32) + (2*8) + 2); + + /* We need to get the frame pointer for the kernel frame that + executes when the signal is raised. This frame is just the + following to the application code that generated the signal, so + that the later's stack pointer is the former's frame pointer. + The stack pointer for the interrupted application code can be + calculated from the ucontext_t structure (third argument for the + signal handler) that is saved in the stack. There are 10 words + between the beginning of the ucontext_t argument of the signal + handler and the uc_mcontext.gregs field that contains the + registers saved by the signal handler. */ + new_cfa = *(void **)(this_cfa + regs_off + (8*10) + (REG_SP*8)); + /* The frame address is %sp + STACK_BIAS in 64-bit mode. */ + new_cfa += 2047; + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = __builtin_dwarf_sp_column (); + fs->regs.cfa_offset = new_cfa - this_cfa; + + /* Restore global and out registers (in this order) from the + ucontext_t structure, uc_mcontext.gregs field. */ + for (i = 1; i < 16; i++) + { + /* We never restore %sp as everything is purely CFA-based. */ + if ((unsigned int) i == __builtin_dwarf_sp_column ()) + continue; + + /* First the global registers and then the out registers. */ + fs->regs.reg[i].how = REG_SAVED_OFFSET; + fs->regs.reg[i].loc.offset + = this_cfa + regs_off + (8*10) + ((REG_Y+i)*8) - new_cfa; + } + + /* Just above the stack pointer there are 16 extended words in which + the register window (in and local registers) was saved. */ + for (i = 0; i < 16; i++) + { + fs->regs.reg[i + 16].how = REG_SAVED_OFFSET; + fs->regs.reg[i + 16].loc.offset = i*8; + } + + /* Check whether we need to restore fpu registers. */ + if (fpu_save) + { + for (i = 0; i < 64; i++) + { + if (i > 32 && (i & 1)) + continue; + + fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; + fs->regs.reg[i + 32].loc.offset + = this_cfa + fpu_save_off + (i*4) - new_cfa; + } + } + + /* State the rules to find the kernel's code "return address", which is + the address of the active instruction when the signal was caught. + On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we + need to preventively subtract it from the purported return address. */ + ra_location = this_cfa + regs_off + (8*10) + (REG_PC*8); + shifted_ra_location = this_cfa + regs_off + (8*10) + (REG_Y*8); + *(void **)shifted_ra_location = *(void **)ra_location - 8; + fs->retaddr_column = 0; + fs->regs.reg[0].how = REG_SAVED_OFFSET; + fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa; + fs->signal_frame = 1; + + return _URC_NO_REASON; +} + +#define MD_FROB_UPDATE_CONTEXT sparc64_frob_update_context + +static void +sparc64_frob_update_context (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + /* The column of %sp contains the old CFA, not the old value of %sp. + The CFA offset already comprises the stack bias so, when %sp is the + CFA register, we must avoid counting the stack bias twice. Do not + do that for signal frames as the offset is artificial for them. */ + if (fs->regs.cfa_reg == __builtin_dwarf_sp_column () + && fs->regs.cfa_how == CFA_REG_OFFSET + && fs->regs.cfa_offset != 0 + && !fs->signal_frame) + context->cfa -= 2047; +} + +#else + +#define MD_FALLBACK_FRAME_STATE_FOR sparc_fallback_frame_state + +static _Unwind_Reason_Code +sparc_fallback_frame_state (struct _Unwind_Context *context, + _Unwind_FrameState *fs) +{ + void *pc = context->ra; + void *this_cfa = context->cfa; + void *new_cfa, *ra_location, *shifted_ra_location; + int regs_off; + int fpu_save_off; + unsigned char fpu_save; + int i; + + /* This is the observed pattern for the sigacthandler. */ + unsigned int sigacthandler_pattern [] + = {0x9602400f, 0x92100019, 0x00000000, 0x912e2002, + 0xe002000a, 0x90100018, 0x9fc40000, 0x9410001a, + 0x80a62008}; + + /* This is the observed pattern for the __libthread_segvhdlr. */ + unsigned int segvhdlr_pattern [] + = {0x94102000, 0xe007bfe4, 0x9010001c, 0x92100019, + 0x9fc40000, 0x9410001a, 0x81c7e008, 0x81e80000, + 0x80a26000}; + + /* This is the observed pattern for the __sighndlr. */ + unsigned int sighndlr_pattern [] + = {0x9de3bfa0, 0x90100018, 0x92100019, 0x9fc6c000, + 0x9410001a, 0x81c7e008, 0x81e80000}; + + /* Deal with frame-less function from which a signal was raised. */ + if (_Unwind_IsSignalFrame (context)) + { + /* The CFA is by definition unmodified in this case. */ + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = __builtin_dwarf_sp_column (); + fs->regs.cfa_offset = 0; + + /* This is the canonical RA column. */ + fs->retaddr_column = 15; + + return _URC_NO_REASON; + } + + /* Look for the sigacthandler pattern. The pattern changes slightly + in different versions of the operating system, so we skip the + comparison against pc-(4*6). */ + if ( *(unsigned int *)(pc-(4*8)) == sigacthandler_pattern[0] + && *(unsigned int *)(pc-(4*7)) == sigacthandler_pattern[1] + /* skip pc-(4*6) */ + && *(unsigned int *)(pc-(4*5)) == sigacthandler_pattern[3] + && *(unsigned int *)(pc-(4*4)) == sigacthandler_pattern[4] + && *(unsigned int *)(pc-(4*3)) == sigacthandler_pattern[5] + && *(unsigned int *)(pc-(4*2)) == sigacthandler_pattern[6] + && *(unsigned int *)(pc-(4*1)) == sigacthandler_pattern[7] + && *(unsigned int *)(pc-(4*0)) == sigacthandler_pattern[8] ) + /* We need to move up two frames (the kernel frame and the handler + frame). Minimum stack frame size is 96 bytes (64 + 4 + 24): 64 + bytes for spilling register window (16 words for in and local + registers), 4 bytes for a pointer to space for callees + returning structs, and 24 bytes to store at least six argument + to callees. The ucontext_t structure is after this offset. */ + regs_off = 96 + 96; + + /* Look for the __libthread_segvhdlr pattern. */ + else if ( *(unsigned int *)(pc-(4*6)) == segvhdlr_pattern[0] + && *(unsigned int *)(pc-(4*5)) == segvhdlr_pattern[1] + && *(unsigned int *)(pc-(4*4)) == segvhdlr_pattern[2] + && *(unsigned int *)(pc-(4*3)) == segvhdlr_pattern[3] + && *(unsigned int *)(pc-(4*2)) == segvhdlr_pattern[4] + && *(unsigned int *)(pc-(4*1)) == segvhdlr_pattern[5] + && *(unsigned int *)(pc-(4*0)) == segvhdlr_pattern[6] + && *(unsigned int *)(pc+(4*1)) == segvhdlr_pattern[7] + && *(unsigned int *)(pc+(4*2)) == segvhdlr_pattern[8] ) + /* We need to move up four frames (the kernel frame, the + sigacthandler frame, the __sighndlr frame, and the + __libthread_segvhdlr). Two of them have the minimum + stack frame size (kernel and __sighndlr frames) of 96 bytes, + other has a stack frame of 216 bytes (the sigacthandler frame), + and there is another with a stack frame of 128 bytes (the + __libthread_segvhdlr). The ucontext_t structure is after this + offset. */ + regs_off = 96 + 96 + 128 + 216; + + /* Look for the __sighndlr pattern. */ + else if ( *(unsigned int *)(pc-(4*5)) == sighndlr_pattern[0] + && *(unsigned int *)(pc-(4*4)) == sighndlr_pattern[1] + && *(unsigned int *)(pc-(4*3)) == sighndlr_pattern[2] + && *(unsigned int *)(pc-(4*2)) == sighndlr_pattern[3] + && *(unsigned int *)(pc-(4*1)) == sighndlr_pattern[4] + && *(unsigned int *)(pc-(4*0)) == sighndlr_pattern[5] + && *(unsigned int *)(pc+(4*1)) == sighndlr_pattern[6] ) + { + /* We have observed different calling frames among different + versions of the operating system, so that we need to + discriminate using the upper frame. We look for the return + address of the caller frame (there is an offset of 15 words + between the frame address and the place where this return + address is stored) in order to do some more pattern matching. */ + unsigned int cuh_pattern + = *(unsigned int *)(*(unsigned int *)(this_cfa + 15*4) - 4); + + if (cuh_pattern == 0xd407a04c) + /* This matches the call_user_handler pattern for Solaris 10. + We need to move up three frames (the kernel frame, the + call_user_handler frame, the __sighndlr frame). Two of them + have the minimum stack frame size (kernel and __sighndlr + frames) of 96 bytes, and there is another with a stack frame + of 160 bytes (the call_user_handler frame). The ucontext_t + structure is after this offset. */ + regs_off = 96 + 96 + 160; + else if (cuh_pattern == 0x9410001a || cuh_pattern == 0x9410001b) + /* This matches the call_user_handler pattern for Solaris 9 and + for Solaris 8 running inside Solaris Containers respectively. + We need to move up four frames (the kernel frame, the signal + frame, the call_user_handler frame, the __sighndlr frame). + Three of them have the minimum stack frame size (kernel, + signal, and __sighndlr frames) of 96 bytes, and there is + another with a stack frame of 160 bytes (the call_user_handler + frame). The ucontext_t structure is after this offset. */ + regs_off = 96 + 96 + 96 + 160; + else + /* We need to move up three frames (the kernel frame, the + sigacthandler frame, and the __sighndlr frame). Two of them + have the minimum stack frame size (kernel and __sighndlr + frames) of 96 bytes, and there is another with a stack frame + of 216 bytes (the sigacthandler frame). The ucontext_t + structure is after this offset. */ + regs_off = 96 + 96 + 216; + } + + /* Exit if the pattern at the return address does not match the + previous three patterns. */ + else + return _URC_END_OF_STACK; + + /* FPU information can be extracted from the ucontext_t structure + that is the third argument for the signal handler, that is saved + in the stack. There are 10 words between the beginning of the + ucontext_t argument of the signal handler and the uc_mcontext + field. There are 80 bytes between the beginning of uc_mcontext + and the beginning of the fpregs field. */ + fpu_save_off = regs_off + (4*10) + (4*20); + + /* The fpregs field contains 32 words at the beginning that contain + the fpu state. Then there are 2 words and two bytes. */ + fpu_save = *(unsigned char *)(this_cfa + fpu_save_off + (4*32) + (2*4) + 2); + + /* We need to get the frame pointer for the kernel frame that + executes when the signal is raised. This frame is just the + following to the application code that generated the signal, so + that the later's stack pointer is the former's frame pointer. + The stack pointer for the interrupted application code can be + calculated from the ucontext_t structure (third argument for the + signal handler) that is saved in the stack. There are 10 words + between the beginning of the ucontext_t argument of the signal + handler and the uc_mcontext.gregs field that contains the + registers saved by the signal handler. */ + new_cfa = *(void **)(this_cfa + regs_off + (4*10) + (REG_SP*4)); + fs->regs.cfa_how = CFA_REG_OFFSET; + fs->regs.cfa_reg = __builtin_dwarf_sp_column (); + fs->regs.cfa_offset = new_cfa - this_cfa; + + /* Restore global and out registers (in this order) from the + ucontext_t structure, uc_mcontext.gregs field. */ + for (i = 1; i < 16; i++) + { + /* We never restore %sp as everything is purely CFA-based. */ + if ((unsigned int) i == __builtin_dwarf_sp_column ()) + continue; + + /* First the global registers and then the out registers */ + fs->regs.reg[i].how = REG_SAVED_OFFSET; + fs->regs.reg[i].loc.offset + = this_cfa + regs_off + (4*10) + ((REG_Y+i)*4) - new_cfa; + } + + /* Just above the stack pointer there are 16 words in which the + register window (in and local registers) was saved. */ + for (i = 0; i < 16; i++) + { + fs->regs.reg[i + 16].how = REG_SAVED_OFFSET; + fs->regs.reg[i + 16].loc.offset = i*4; + } + + /* Check whether we need to restore fpu registers. */ + if (fpu_save) + { + for (i = 0; i < 32; i++) + { + fs->regs.reg[i + 32].how = REG_SAVED_OFFSET; + fs->regs.reg[i + 32].loc.offset + = this_cfa + fpu_save_off + (i*4) - new_cfa; + } + } + + /* State the rules to find the kernel's code "return address", which is + the address of the active instruction when the signal was caught. + On the SPARC, since RETURN_ADDR_OFFSET (essentially 8) is defined, we + need to preventively subtract it from the purported return address. */ + ra_location = this_cfa + regs_off + (4*10) + (REG_PC*4); + shifted_ra_location = this_cfa + regs_off + (4*10) + (REG_Y*4); + *(void **)shifted_ra_location = *(void **)ra_location - 8; + fs->retaddr_column = 0; + fs->regs.reg[0].how = REG_SAVED_OFFSET; + fs->regs.reg[0].loc.offset = shifted_ra_location - new_cfa; + fs->signal_frame = 1; + + return _URC_NO_REASON; +}; + +#endif diff --git a/gcc/config/sparc/sol2.h b/gcc/config/sparc/sol2.h index 139f5b39dff..a3f7647027b 100644 --- a/gcc/config/sparc/sol2.h +++ b/gcc/config/sparc/sol2.h @@ -194,3 +194,5 @@ along with GCC; see the file COPYING3. If not see (SIZE), (ALIGN) / BITS_PER_UNIT); \ } \ while (0) + +#define MD_UNWIND_SUPPORT "config/sparc/sol2-unwind.h" diff --git a/gcc/config/spu/cache.S b/gcc/config/spu/cache.S new file mode 100644 index 00000000000..9ffb6a0d194 --- /dev/null +++ b/gcc/config/spu/cache.S @@ -0,0 +1,43 @@ +/* Copyright (C) 2008, 2009 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 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + + .data + .p2align 7 + .global __cache +__cache: + .rept __CACHE_SIZE__ * 8 + .fill 128 + .endr + + .p2align 7 + .global __cache_tag_array +__cache_tag_array: + .rept __CACHE_SIZE__ * 2 + .long 1, 1, 1, 1 + .fill 128-16 + .endr +__end_cache_tag_array: + + .globl __cache_tag_array_size + .set __cache_tag_array_size, __end_cache_tag_array-__cache_tag_array + diff --git a/gcc/config/spu/cachemgr.c b/gcc/config/spu/cachemgr.c new file mode 100644 index 00000000000..e7abd5e62db --- /dev/null +++ b/gcc/config/spu/cachemgr.c @@ -0,0 +1,438 @@ +/* Copyright (C) 2008, 2009 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 3, 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. + +Under Section 7 of GPL version 3, you are granted additional +permissions described in the GCC Runtime Library Exception, version +3.1, as published by the Free Software Foundation. + +You should have received a copy of the GNU General Public License and +a copy of the GCC Runtime Library Exception along with this program; +see the files COPYING3 and COPYING.RUNTIME respectively. If not, see +. */ + +#include +#include +#include +#include + +extern unsigned long long __ea_local_store; +extern char __cache_tag_array_size; + +#define LINE_SIZE 128 +#define TAG_MASK (LINE_SIZE - 1) + +#define WAYS 4 +#define SET_MASK ((int) &__cache_tag_array_size - LINE_SIZE) + +#define CACHE_LINES ((int) &__cache_tag_array_size / \ + sizeof (struct __cache_tag_array) * WAYS) + +struct __cache_tag_array +{ + unsigned int tag_lo[WAYS]; + unsigned int tag_hi[WAYS]; + void *base[WAYS]; + int reserved[WAYS]; + vector unsigned short dirty_bits[WAYS]; +}; + +extern struct __cache_tag_array __cache_tag_array[]; +extern char __cache[]; + +/* In order to make the code seem a little cleaner, and to avoid having + 64/32 bit ifdefs all over the place, we use macros. */ + +#ifdef __EA64__ +typedef unsigned long long addr; + +#define CHECK_TAG(_entry, _way, _tag) \ + ((_entry)->tag_lo[(_way)] == ((_tag) & 0xFFFFFFFF) \ + && (_entry)->tag_hi[(_way)] == ((_tag) >> 32)) + +#define GET_TAG(_entry, _way) \ + ((unsigned long long)(_entry)->tag_hi[(_way)] << 32 \ + | (unsigned long long)(_entry)->tag_lo[(_way)]) + +#define SET_TAG(_entry, _way, _tag) \ + (_entry)->tag_lo[(_way)] = (_tag) & 0xFFFFFFFF; \ + (_entry)->tag_hi[(_way)] = (_tag) >> 32 + +#else /*__EA32__*/ +typedef unsigned long addr; + +#define CHECK_TAG(_entry, _way, _tag) \ + ((_entry)->tag_lo[(_way)] == (_tag)) + +#define GET_TAG(_entry, _way) \ + ((_entry)->tag_lo[(_way)]) + +#define SET_TAG(_entry, _way, _tag) \ + (_entry)->tag_lo[(_way)] = (_tag) + +#endif + +/* In GET_ENTRY, we cast away the high 32 bits, + as the tag is only in the low 32. */ + +#define GET_ENTRY(_addr) \ + ((struct __cache_tag_array *) \ + si_to_uint (si_a (si_and (si_from_uint ((unsigned int) (addr) (_addr)), \ + si_from_uint (SET_MASK)), \ + si_from_uint ((unsigned int) __cache_tag_array)))) + +#define GET_CACHE_LINE(_addr, _way) \ + ((void *) (__cache + ((_addr) & SET_MASK) * WAYS) + ((_way) * LINE_SIZE)); + +#define CHECK_DIRTY(_vec) (si_to_uint (si_orx ((qword) (_vec)))) +#define SET_EMPTY(_entry, _way) ((_entry)->tag_lo[(_way)] = 1) +#define CHECK_EMPTY(_entry, _way) ((_entry)->tag_lo[(_way)] == 1) + +#define LS_FLAG 0x80000000 +#define SET_IS_LS(_entry, _way) ((_entry)->reserved[(_way)] |= LS_FLAG) +#define CHECK_IS_LS(_entry, _way) ((_entry)->reserved[(_way)] & LS_FLAG) +#define GET_LRU(_entry, _way) ((_entry)->reserved[(_way)] & ~LS_FLAG) + +static int dma_tag = 32; + +static void +__cache_evict_entry (struct __cache_tag_array *entry, int way) +{ + addr tag = GET_TAG (entry, way); + + if (CHECK_DIRTY (entry->dirty_bits[way]) && !CHECK_IS_LS (entry, way)) + { +#ifdef NONATOMIC + /* Non-atomic writes. */ + unsigned int oldmask, mach_stat; + char *line = ((void *) 0); + + /* Enter critical section. */ + mach_stat = spu_readch (SPU_RdMachStat); + spu_idisable (); + + /* Issue DMA request. */ + line = GET_CACHE_LINE (entry->tag_lo[way], way); + mfc_put (line, tag, LINE_SIZE, dma_tag, 0, 0); + + /* Wait for DMA completion. */ + oldmask = mfc_read_tag_mask (); + mfc_write_tag_mask (1 << dma_tag); + mfc_read_tag_status_all (); + mfc_write_tag_mask (oldmask); + + /* Leave critical section. */ + if (__builtin_expect (mach_stat & 1, 0)) + spu_ienable (); +#else + /* Allocate a buffer large enough that we know it has 128 bytes + that are 128 byte aligned (for DMA). */ + + char buffer[LINE_SIZE + 127]; + qword *buf_ptr = (qword *) (((unsigned int) (buffer) + 127) & ~127); + qword *line = GET_CACHE_LINE (entry->tag_lo[way], way); + qword bits; + unsigned int mach_stat; + + /* Enter critical section. */ + mach_stat = spu_readch (SPU_RdMachStat); + spu_idisable (); + + do + { + /* We atomically read the current memory into a buffer + modify the dirty bytes in the buffer, and write it + back. If writeback fails, loop and try again. */ + + mfc_getllar (buf_ptr, tag, 0, 0); + mfc_read_atomic_status (); + + /* The method we're using to write 16 dirty bytes into + the buffer at a time uses fsmb which in turn uses + the least significant 16 bits of word 0, so we + load the bits and rotate so that the first bit of + the bitmap is in the first bit that fsmb will use. */ + + bits = (qword) entry->dirty_bits[way]; + bits = si_rotqbyi (bits, -2); + + /* Si_fsmb creates the mask of dirty bytes. + Use selb to nab the appropriate bits. */ + buf_ptr[0] = si_selb (buf_ptr[0], line[0], si_fsmb (bits)); + + /* Rotate to next 16 byte section of cache. */ + bits = si_rotqbyi (bits, 2); + + buf_ptr[1] = si_selb (buf_ptr[1], line[1], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[2] = si_selb (buf_ptr[2], line[2], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[3] = si_selb (buf_ptr[3], line[3], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[4] = si_selb (buf_ptr[4], line[4], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[5] = si_selb (buf_ptr[5], line[5], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[6] = si_selb (buf_ptr[6], line[6], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + buf_ptr[7] = si_selb (buf_ptr[7], line[7], si_fsmb (bits)); + bits = si_rotqbyi (bits, 2); + + mfc_putllc (buf_ptr, tag, 0, 0); + } + while (mfc_read_atomic_status ()); + + /* Leave critical section. */ + if (__builtin_expect (mach_stat & 1, 0)) + spu_ienable (); +#endif + } + + /* In any case, marking the lo tag with 1 which denotes empty. */ + SET_EMPTY (entry, way); + entry->dirty_bits[way] = (vector unsigned short) si_from_uint (0); +} + +void +__cache_evict (__ea void *ea) +{ + addr tag = (addr) ea & ~TAG_MASK; + struct __cache_tag_array *entry = GET_ENTRY (ea); + int i = 0; + + /* Cycles through all the possible ways an address could be at + and evicts the way if found. */ + + for (i = 0; i < WAYS; i++) + if (CHECK_TAG (entry, i, tag)) + __cache_evict_entry (entry, i); +} + +static void * +__cache_fill (int way, addr tag) +{ + unsigned int oldmask, mach_stat; + char *line = ((void *) 0); + + /* Reserve our DMA tag. */ + if (dma_tag == 32) + dma_tag = mfc_tag_reserve (); + + /* Enter critical section. */ + mach_stat = spu_readch (SPU_RdMachStat); + spu_idisable (); + + /* Issue DMA request. */ + line = GET_CACHE_LINE (tag, way); + mfc_get (line, tag, LINE_SIZE, dma_tag, 0, 0); + + /* Wait for DMA completion. */ + oldmask = mfc_read_tag_mask (); + mfc_write_tag_mask (1 << dma_tag); + mfc_read_tag_status_all (); + mfc_write_tag_mask (oldmask); + + /* Leave critical section. */ + if (__builtin_expect (mach_stat & 1, 0)) + spu_ienable (); + + return (void *) line; +} + +static void +__cache_miss (__ea void *ea, struct __cache_tag_array *entry, int way) +{ + + addr tag = (addr) ea & ~TAG_MASK; + unsigned int lru = 0; + int i = 0; + int idx = 0; + + /* If way > 4, then there are no empty slots, so we must evict + the least recently used entry. */ + if (way >= 4) + { + for (i = 0; i < WAYS; i++) + { + if (GET_LRU (entry, i) > lru) + { + lru = GET_LRU (entry, i); + idx = i; + } + } + __cache_evict_entry (entry, idx); + way = idx; + } + + /* Set the empty entry's tag and fill it's cache line. */ + + SET_TAG (entry, way, tag); + entry->reserved[way] = 0; + + /* Check if the address is just an effective address within the + SPU's local store. */ + + /* Because the LS is not 256k aligned, we can't do a nice and mask + here to compare, so we must check the whole range. */ + + if ((addr) ea >= (addr) __ea_local_store + && (addr) ea < (addr) (__ea_local_store + 0x40000)) + { + SET_IS_LS (entry, way); + entry->base[way] = + (void *) ((unsigned int) ((addr) ea - + (addr) __ea_local_store) & ~0x7f); + } + else + { + entry->base[way] = __cache_fill (way, tag); + } +} + +void * +__cache_fetch_dirty (__ea void *ea, int n_bytes_dirty) +{ +#ifdef __EA64__ + unsigned int tag_hi; + qword etag_hi; +#endif + unsigned int tag_lo; + struct __cache_tag_array *entry; + + qword etag_lo; + qword equal; + qword bit_mask; + qword way; + + /* This first chunk, we merely fill the pointer and tag. */ + + entry = GET_ENTRY (ea); + +#ifndef __EA64__ + tag_lo = + si_to_uint (si_andc + (si_shufb + (si_from_uint ((addr) ea), si_from_uint (0), + si_from_uint (0x00010203)), si_from_uint (TAG_MASK))); +#else + tag_lo = + si_to_uint (si_andc + (si_shufb + (si_from_ullong ((addr) ea), si_from_uint (0), + si_from_uint (0x04050607)), si_from_uint (TAG_MASK))); + + tag_hi = + si_to_uint (si_shufb + (si_from_ullong ((addr) ea), si_from_uint (0), + si_from_uint (0x00010203))); +#endif + + /* Increment LRU in reserved bytes. */ + si_stqd (si_ai (si_lqd (si_from_ptr (entry), 48), 1), + si_from_ptr (entry), 48); + +missreturn: + /* Check if the entry's lo_tag is equal to the address' lo_tag. */ + etag_lo = si_lqd (si_from_ptr (entry), 0); + equal = si_ceq (etag_lo, si_from_uint (tag_lo)); +#ifdef __EA64__ + /* And the high tag too. */ + etag_hi = si_lqd (si_from_ptr (entry), 16); + equal = si_and (equal, (si_ceq (etag_hi, si_from_uint (tag_hi)))); +#endif + + if ((si_to_uint (si_orx (equal)) == 0)) + goto misshandler; + + if (n_bytes_dirty) + { + /* way = 0x40,0x50,0x60,0x70 for each way, which is also the + offset of the appropriate dirty bits. */ + way = si_shli (si_clz (si_gbb (equal)), 2); + + /* To create the bit_mask, we set it to all 1s (uint -1), then we + shift it over (128 - n_bytes_dirty) times. */ + + bit_mask = si_from_uint (-1); + + bit_mask = + si_shlqby (bit_mask, si_from_uint ((LINE_SIZE - n_bytes_dirty) / 8)); + + bit_mask = + si_shlqbi (bit_mask, si_from_uint ((LINE_SIZE - n_bytes_dirty) % 8)); + + /* Rotate it around to the correct offset. */ + bit_mask = + si_rotqby (bit_mask, + si_from_uint (-1 * ((addr) ea & TAG_MASK) / 8)); + + bit_mask = + si_rotqbi (bit_mask, + si_from_uint (-1 * ((addr) ea & TAG_MASK) % 8)); + + /* Update the dirty bits. */ + si_stqx (si_or (si_lqx (si_from_ptr (entry), way), bit_mask), + si_from_ptr (entry), way); + }; + + /* We've definitely found the right entry, set LRU (reserved) to 0 + maintaining the LS flag (MSB). */ + + si_stqd (si_andc + (si_lqd (si_from_ptr (entry), 48), + si_and (equal, si_from_uint (~(LS_FLAG)))), + si_from_ptr (entry), 48); + + return (void *) + si_to_uint (si_a + (si_orx + (si_and (si_lqd (si_from_ptr (entry), 32), equal)), + si_from_uint (((unsigned int) (addr) ea) & TAG_MASK))); + +misshandler: + equal = si_ceqi (etag_lo, 1); + __cache_miss (ea, entry, (si_to_uint (si_clz (si_gbb (equal))) - 16) >> 2); + goto missreturn; +} + +void * +__cache_fetch (__ea void *ea) +{ + return __cache_fetch_dirty (ea, 0); +} + +void +__cache_touch (__ea void *ea __attribute__ ((unused))) +{ + /* NO-OP for now. */ +} + +void __cache_flush (void) __attribute__ ((destructor)); +void +__cache_flush (void) +{ + struct __cache_tag_array *entry = __cache_tag_array; + unsigned int i; + int j; + + /* Cycle through each cache entry and evict all used ways. */ + + for (i = 0; i < CACHE_LINES / WAYS; i++) + { + for (j = 0; j < WAYS; j++) + if (!CHECK_EMPTY (entry, j)) + __cache_evict_entry (entry, j); + + entry++; + } +} diff --git a/gcc/config/spu/spu-c.c b/gcc/config/spu/spu-c.c index fbbbf32e157..380af402c48 100644 --- a/gcc/config/spu/spu-c.c +++ b/gcc/config/spu/spu-c.c @@ -201,6 +201,17 @@ spu_cpu_cpp_builtins (struct cpp_reader *pfile) if (spu_arch == PROCESSOR_CELLEDP) builtin_define_std ("__SPU_EDP__"); builtin_define_std ("__vector=__attribute__((__spu_vector__))"); + switch (spu_ea_model) + { + case 32: + builtin_define_std ("__EA32__"); + break; + case 64: + builtin_define_std ("__EA64__"); + break; + default: + gcc_unreachable (); + } if (!flag_iso) { diff --git a/gcc/config/spu/spu-elf.h b/gcc/config/spu/spu-elf.h index 532313119cb..68982002103 100644 --- a/gcc/config/spu/spu-elf.h +++ b/gcc/config/spu/spu-elf.h @@ -68,8 +68,14 @@ #define LINK_SPEC "%{mlarge-mem: --defsym __stack=0xfffffff0 }" -#define LIB_SPEC \ - "-( %{!shared:%{g*:-lg}} -lc -lgloss -)" +#define LIB_SPEC "-( %{!shared:%{g*:-lg}} -lc -lgloss -) \ + %{mno-atomic-updates:-lgcc_cachemgr_nonatomic; :-lgcc_cachemgr} \ + %{mcache-size=128:-lgcc_cache128k; \ + mcache-size=64 :-lgcc_cache64k; \ + mcache-size=32 :-lgcc_cache32k; \ + mcache-size=16 :-lgcc_cache16k; \ + mcache-size=8 :-lgcc_cache8k; \ + :-lgcc_cache64k}" /* Turn off warnings in the assembler too. */ #undef ASM_SPEC diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c index 316cc73d777..2888da67281 100644 --- a/gcc/config/spu/spu.c +++ b/gcc/config/spu/spu.c @@ -150,9 +150,12 @@ char regs_ever_allocated[FIRST_PSEUDO_REGISTER]; /* Prototypes and external defs. */ static void spu_init_builtins (void); +static tree spu_builtin_decl (unsigned, bool); static unsigned char spu_scalar_mode_supported_p (enum machine_mode mode); static unsigned char spu_vector_mode_supported_p (enum machine_mode mode); static bool spu_legitimate_address_p (enum machine_mode, rtx, bool); +static bool spu_addr_space_legitimate_address_p (enum machine_mode, rtx, + bool, addr_space_t); static rtx adjust_operand (rtx op, HOST_WIDE_INT * start); static rtx get_pic_reg (void); static int need_to_save_reg (int regno, int saving); @@ -202,15 +205,23 @@ static bool spu_return_in_memory (const_tree type, const_tree fntype); static void fix_range (const char *); static void spu_encode_section_info (tree, rtx, int); static rtx spu_legitimize_address (rtx, rtx, enum machine_mode); +static rtx spu_addr_space_legitimize_address (rtx, rtx, enum machine_mode, + addr_space_t); static tree spu_builtin_mul_widen_even (tree); static tree spu_builtin_mul_widen_odd (tree); static tree spu_builtin_mask_for_load (void); static int spu_builtin_vectorization_cost (bool); static bool spu_vector_alignment_reachable (const_tree, bool); static tree spu_builtin_vec_perm (tree, tree *); +static enum machine_mode spu_addr_space_pointer_mode (addr_space_t); +static enum machine_mode spu_addr_space_address_mode (addr_space_t); +static bool spu_addr_space_subset_p (addr_space_t, addr_space_t); +static rtx spu_addr_space_convert (rtx, tree, tree); static int spu_sms_res_mii (struct ddg *g); static void asm_file_start (void); static unsigned int spu_section_type_flags (tree, const char *, int); +static section *spu_select_section (tree, int, unsigned HOST_WIDE_INT); +static void spu_unique_section (tree, int); static rtx spu_expand_load (rtx, rtx, rtx, int); static void spu_trampoline_init (rtx, tree, rtx); @@ -269,6 +280,10 @@ spu_libgcc_cmp_return_mode (void); static enum machine_mode spu_libgcc_shift_count_mode (void); + +/* Pointer mode for __ea references. */ +#define EAmode (spu_ea_model != 32 ? DImode : SImode) + /* Table of machine attributes. */ static const struct attribute_spec spu_attribute_table[] = @@ -281,8 +296,29 @@ static const struct attribute_spec spu_attribute_table[] = /* TARGET overrides. */ +#undef TARGET_ADDR_SPACE_POINTER_MODE +#define TARGET_ADDR_SPACE_POINTER_MODE spu_addr_space_pointer_mode + +#undef TARGET_ADDR_SPACE_ADDRESS_MODE +#define TARGET_ADDR_SPACE_ADDRESS_MODE spu_addr_space_address_mode + +#undef TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P +#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P \ + spu_addr_space_legitimate_address_p + +#undef TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS +#define TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS spu_addr_space_legitimize_address + +#undef TARGET_ADDR_SPACE_SUBSET_P +#define TARGET_ADDR_SPACE_SUBSET_P spu_addr_space_subset_p + +#undef TARGET_ADDR_SPACE_CONVERT +#define TARGET_ADDR_SPACE_CONVERT spu_addr_space_convert + #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS spu_init_builtins +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL spu_builtin_decl #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN spu_expand_builtin @@ -293,6 +329,15 @@ static const struct attribute_spec spu_attribute_table[] = #undef TARGET_LEGITIMIZE_ADDRESS #define TARGET_LEGITIMIZE_ADDRESS spu_legitimize_address +/* The current assembler doesn't like .4byte foo@ppu, so use the normal .long + and .quad for the debugger. When it is known that the assembler is fixed, + these can be removed. */ +#undef TARGET_ASM_UNALIGNED_SI_OP +#define TARGET_ASM_UNALIGNED_SI_OP "\t.long\t" + +#undef TARGET_ASM_ALIGNED_DI_OP +#define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t" + /* The .8byte directive doesn't seem to work well for a 32 bit architecture. */ #undef TARGET_ASM_UNALIGNED_DI_OP @@ -409,6 +454,12 @@ static const struct attribute_spec spu_attribute_table[] = #undef TARGET_SECTION_TYPE_FLAGS #define TARGET_SECTION_TYPE_FLAGS spu_section_type_flags +#undef TARGET_ASM_SELECT_SECTION +#define TARGET_ASM_SELECT_SECTION spu_select_section + +#undef TARGET_ASM_UNIQUE_SECTION +#define TARGET_ASM_UNIQUE_SECTION spu_unique_section + #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P spu_legitimate_address_p @@ -2365,7 +2416,7 @@ get_branch_target (rtx branch) return 0; /* ASM GOTOs. */ - if (GET_CODE (PATTERN (branch)) == ASM_OPERANDS) + if (extract_asm_operands (PATTERN (branch)) != NULL) return NULL; set = single_set (branch); @@ -3610,6 +3661,29 @@ exp2_immediate_p (rtx op, enum machine_mode mode, int low, int high) return FALSE; } +/* Return true if X is a SYMBOL_REF to an __ea qualified variable. */ + +static int +ea_symbol_ref (rtx *px, void *data ATTRIBUTE_UNUSED) +{ + rtx x = *px; + tree decl; + + if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS) + { + rtx plus = XEXP (x, 0); + rtx op0 = XEXP (plus, 0); + rtx op1 = XEXP (plus, 1); + if (GET_CODE (op1) == CONST_INT) + x = op0; + } + + return (GET_CODE (x) == SYMBOL_REF + && (decl = SYMBOL_REF_DECL (x)) != 0 + && TREE_CODE (decl) == VAR_DECL + && TYPE_ADDR_SPACE (TREE_TYPE (decl))); +} + /* We accept: - any 32-bit constant (SImode, SFmode) - any constant that can be generated with fsmbi (any mode) @@ -3621,6 +3695,12 @@ spu_legitimate_constant_p (rtx x) { if (GET_CODE (x) == HIGH) x = XEXP (x, 0); + + /* Reject any __ea qualified reference. These can't appear in + instructions but must be forced to the constant pool. */ + if (for_each_rtx (&x, ea_symbol_ref, 0)) + return 0; + /* V4SI with all identical symbols is valid. */ if (!flag_pic && GET_MODE (x) == V4SImode @@ -3659,8 +3739,14 @@ spu_legitimate_address_p (enum machine_mode mode, switch (GET_CODE (x)) { case LABEL_REF: + return !TARGET_LARGE_MEM; + case SYMBOL_REF: case CONST: + /* Keep __ea references until reload so that spu_expand_mov can see them + in MEMs. */ + if (ea_symbol_ref (&x, 0)) + return !reload_in_progress && !reload_completed; return !TARGET_LARGE_MEM; case CONST_INT: @@ -3704,6 +3790,20 @@ spu_legitimate_address_p (enum machine_mode mode, return FALSE; } +/* Like spu_legitimate_address_p, except with named addresses. */ +static bool +spu_addr_space_legitimate_address_p (enum machine_mode mode, rtx x, + bool reg_ok_strict, addr_space_t as) +{ + if (as == ADDR_SPACE_EA) + return (REG_P (x) && (GET_MODE (x) == EAmode)); + + else if (as != ADDR_SPACE_GENERIC) + gcc_unreachable (); + + return spu_legitimate_address_p (mode, x, reg_ok_strict); +} + /* When the address is reg + const_int, force the const_int into a register. */ rtx @@ -3735,6 +3835,17 @@ spu_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED, return x; } +/* Like spu_legitimate_address, except with named address support. */ +static rtx +spu_addr_space_legitimize_address (rtx x, rtx oldx, enum machine_mode mode, + addr_space_t as) +{ + if (as != ADDR_SPACE_GENERIC) + return x; + + return spu_legitimize_address (x, oldx, mode); +} + /* Handle an attribute requiring a FUNCTION_DECL; arguments as in struct attribute_spec.handler. */ static tree @@ -4238,6 +4349,233 @@ address_needs_split (rtx mem) return 0; } +static GTY(()) rtx cache_fetch; /* __cache_fetch function */ +static GTY(()) rtx cache_fetch_dirty; /* __cache_fetch_dirty function */ +static alias_set_type ea_alias_set = -1; /* alias set for __ea memory */ + +/* MEM is known to be an __ea qualified memory access. Emit a call to + fetch the ppu memory to local store, and return its address in local + store. */ + +static void +ea_load_store (rtx mem, bool is_store, rtx ea_addr, rtx data_addr) +{ + if (is_store) + { + rtx ndirty = GEN_INT (GET_MODE_SIZE (GET_MODE (mem))); + if (!cache_fetch_dirty) + cache_fetch_dirty = init_one_libfunc ("__cache_fetch_dirty"); + emit_library_call_value (cache_fetch_dirty, data_addr, LCT_NORMAL, Pmode, + 2, ea_addr, EAmode, ndirty, SImode); + } + else + { + if (!cache_fetch) + cache_fetch = init_one_libfunc ("__cache_fetch"); + emit_library_call_value (cache_fetch, data_addr, LCT_NORMAL, Pmode, + 1, ea_addr, EAmode); + } +} + +/* Like ea_load_store, but do the cache tag comparison and, for stores, + dirty bit marking, inline. + + The cache control data structure is an array of + + struct __cache_tag_array + { + unsigned int tag_lo[4]; + unsigned int tag_hi[4]; + void *data_pointer[4]; + int reserved[4]; + vector unsigned short dirty_bits[4]; + } */ + +static void +ea_load_store_inline (rtx mem, bool is_store, rtx ea_addr, rtx data_addr) +{ + rtx ea_addr_si; + HOST_WIDE_INT v; + rtx tag_size_sym = gen_rtx_SYMBOL_REF (Pmode, "__cache_tag_array_size"); + rtx tag_arr_sym = gen_rtx_SYMBOL_REF (Pmode, "__cache_tag_array"); + rtx index_mask = gen_reg_rtx (SImode); + rtx tag_arr = gen_reg_rtx (Pmode); + rtx splat_mask = gen_reg_rtx (TImode); + rtx splat = gen_reg_rtx (V4SImode); + rtx splat_hi = NULL_RTX; + rtx tag_index = gen_reg_rtx (Pmode); + rtx block_off = gen_reg_rtx (SImode); + rtx tag_addr = gen_reg_rtx (Pmode); + rtx tag = gen_reg_rtx (V4SImode); + rtx cache_tag = gen_reg_rtx (V4SImode); + rtx cache_tag_hi = NULL_RTX; + rtx cache_ptrs = gen_reg_rtx (TImode); + rtx cache_ptrs_si = gen_reg_rtx (SImode); + rtx tag_equal = gen_reg_rtx (V4SImode); + rtx tag_equal_hi = NULL_RTX; + rtx tag_eq_pack = gen_reg_rtx (V4SImode); + rtx tag_eq_pack_si = gen_reg_rtx (SImode); + rtx eq_index = gen_reg_rtx (SImode); + rtx bcomp, hit_label, hit_ref, cont_label, insn; + + if (spu_ea_model != 32) + { + splat_hi = gen_reg_rtx (V4SImode); + cache_tag_hi = gen_reg_rtx (V4SImode); + tag_equal_hi = gen_reg_rtx (V4SImode); + } + + emit_move_insn (index_mask, plus_constant (tag_size_sym, -128)); + emit_move_insn (tag_arr, tag_arr_sym); + v = 0x0001020300010203LL; + emit_move_insn (splat_mask, immed_double_const (v, v, TImode)); + ea_addr_si = ea_addr; + if (spu_ea_model != 32) + ea_addr_si = convert_to_mode (SImode, ea_addr, 1); + + /* tag_index = ea_addr & (tag_array_size - 128) */ + emit_insn (gen_andsi3 (tag_index, ea_addr_si, index_mask)); + + /* splat ea_addr to all 4 slots. */ + emit_insn (gen_shufb (splat, ea_addr_si, ea_addr_si, splat_mask)); + /* Similarly for high 32 bits of ea_addr. */ + if (spu_ea_model != 32) + emit_insn (gen_shufb (splat_hi, ea_addr, ea_addr, splat_mask)); + + /* block_off = ea_addr & 127 */ + emit_insn (gen_andsi3 (block_off, ea_addr_si, spu_const (SImode, 127))); + + /* tag_addr = tag_arr + tag_index */ + emit_insn (gen_addsi3 (tag_addr, tag_arr, tag_index)); + + /* Read cache tags. */ + emit_move_insn (cache_tag, gen_rtx_MEM (V4SImode, tag_addr)); + if (spu_ea_model != 32) + emit_move_insn (cache_tag_hi, gen_rtx_MEM (V4SImode, + plus_constant (tag_addr, 16))); + + /* tag = ea_addr & -128 */ + emit_insn (gen_andv4si3 (tag, splat, spu_const (V4SImode, -128))); + + /* Read all four cache data pointers. */ + emit_move_insn (cache_ptrs, gen_rtx_MEM (TImode, + plus_constant (tag_addr, 32))); + + /* Compare tags. */ + emit_insn (gen_ceq_v4si (tag_equal, tag, cache_tag)); + if (spu_ea_model != 32) + { + emit_insn (gen_ceq_v4si (tag_equal_hi, splat_hi, cache_tag_hi)); + emit_insn (gen_andv4si3 (tag_equal, tag_equal, tag_equal_hi)); + } + + /* At most one of the tags compare equal, so tag_equal has one + 32-bit slot set to all 1's, with the other slots all zero. + gbb picks off low bit from each byte in the 128-bit registers, + so tag_eq_pack is one of 0xf000, 0x0f00, 0x00f0, 0x000f, assuming + we have a hit. */ + emit_insn (gen_spu_gbb (tag_eq_pack, spu_gen_subreg (V16QImode, tag_equal))); + emit_insn (gen_spu_convert (tag_eq_pack_si, tag_eq_pack)); + + /* So counting leading zeros will set eq_index to 16, 20, 24 or 28. */ + emit_insn (gen_clzsi2 (eq_index, tag_eq_pack_si)); + + /* Allowing us to rotate the corresponding cache data pointer to slot0. + (rotating eq_index mod 16 bytes). */ + emit_insn (gen_rotqby_ti (cache_ptrs, cache_ptrs, eq_index)); + emit_insn (gen_spu_convert (cache_ptrs_si, cache_ptrs)); + + /* Add block offset to form final data address. */ + emit_insn (gen_addsi3 (data_addr, cache_ptrs_si, block_off)); + + /* Check that we did hit. */ + hit_label = gen_label_rtx (); + hit_ref = gen_rtx_LABEL_REF (VOIDmode, hit_label); + bcomp = gen_rtx_NE (SImode, tag_eq_pack_si, const0_rtx); + insn = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, bcomp, + hit_ref, pc_rtx))); + /* Say that this branch is very likely to happen. */ + v = REG_BR_PROB_BASE - REG_BR_PROB_BASE / 100 - 1; + REG_NOTES (insn) + = gen_rtx_EXPR_LIST (REG_BR_PROB, GEN_INT (v), REG_NOTES (insn)); + + ea_load_store (mem, is_store, ea_addr, data_addr); + cont_label = gen_label_rtx (); + emit_jump_insn (gen_jump (cont_label)); + emit_barrier (); + + emit_label (hit_label); + + if (is_store) + { + HOST_WIDE_INT v_hi; + rtx dirty_bits = gen_reg_rtx (TImode); + rtx dirty_off = gen_reg_rtx (SImode); + rtx dirty_128 = gen_reg_rtx (TImode); + rtx neg_block_off = gen_reg_rtx (SImode); + + /* Set up mask with one dirty bit per byte of the mem we are + writing, starting from top bit. */ + v_hi = v = -1; + v <<= (128 - GET_MODE_SIZE (GET_MODE (mem))) & 63; + if ((128 - GET_MODE_SIZE (GET_MODE (mem))) >= 64) + { + v_hi = v; + v = 0; + } + emit_move_insn (dirty_bits, immed_double_const (v, v_hi, TImode)); + + /* Form index into cache dirty_bits. eq_index is one of + 0x10, 0x14, 0x18 or 0x1c. Multiplying by 4 gives us + 0x40, 0x50, 0x60 or 0x70 which just happens to be the + offset to each of the four dirty_bits elements. */ + emit_insn (gen_ashlsi3 (dirty_off, eq_index, spu_const (SImode, 2))); + + emit_insn (gen_spu_lqx (dirty_128, tag_addr, dirty_off)); + + /* Rotate bit mask to proper bit. */ + emit_insn (gen_negsi2 (neg_block_off, block_off)); + emit_insn (gen_rotqbybi_ti (dirty_bits, dirty_bits, neg_block_off)); + emit_insn (gen_rotqbi_ti (dirty_bits, dirty_bits, neg_block_off)); + + /* Or in the new dirty bits. */ + emit_insn (gen_iorti3 (dirty_128, dirty_bits, dirty_128)); + + /* Store. */ + emit_insn (gen_spu_stqx (dirty_128, tag_addr, dirty_off)); + } + + emit_label (cont_label); +} + +static rtx +expand_ea_mem (rtx mem, bool is_store) +{ + rtx ea_addr; + rtx data_addr = gen_reg_rtx (Pmode); + rtx new_mem; + + ea_addr = force_reg (EAmode, XEXP (mem, 0)); + if (optimize_size || optimize == 0) + ea_load_store (mem, is_store, ea_addr, data_addr); + else + ea_load_store_inline (mem, is_store, ea_addr, data_addr); + + if (ea_alias_set == -1) + ea_alias_set = new_alias_set (); + + /* We generate a new MEM RTX to refer to the copy of the data + in the cache. We do not copy memory attributes (except the + alignment) from the original MEM, as they may no longer apply + to the cache copy. */ + new_mem = gen_rtx_MEM (GET_MODE (mem), data_addr); + set_mem_alias_set (new_mem, ea_alias_set); + set_mem_align (new_mem, MIN (MEM_ALIGN (mem), 128 * 8)); + + return new_mem; +} + int spu_expand_mov (rtx * ops, enum machine_mode mode) { @@ -4295,9 +4633,17 @@ spu_expand_mov (rtx * ops, enum machine_mode mode) } } if (MEM_P (ops[0])) - return spu_split_store (ops); + { + if (MEM_ADDR_SPACE (ops[0])) + ops[0] = expand_ea_mem (ops[0], true); + return spu_split_store (ops); + } if (MEM_P (ops[1])) - return spu_split_load (ops); + { + if (MEM_ADDR_SPACE (ops[1])) + ops[1] = expand_ea_mem (ops[1], false); + return spu_split_load (ops); + } return 0; } @@ -5285,6 +5631,18 @@ struct spu_builtin_description spu_builtins[] = { #undef DEF_BUILTIN }; +/* Returns the rs6000 builtin decl for CODE. */ + +static tree +spu_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= NUM_SPU_BUILTINS) + return error_mark_node; + + return spu_builtins[code].fndecl; +} + + static void spu_init_builtins (void) { @@ -6427,6 +6785,113 @@ spu_builtin_vec_perm (tree type, tree *mask_element_type) return d->fndecl; } +/* Return the appropriate mode for a named address pointer. */ +static enum machine_mode +spu_addr_space_pointer_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + case ADDR_SPACE_GENERIC: + return ptr_mode; + case ADDR_SPACE_EA: + return EAmode; + default: + gcc_unreachable (); + } +} + +/* Return the appropriate mode for a named address address. */ +static enum machine_mode +spu_addr_space_address_mode (addr_space_t addrspace) +{ + switch (addrspace) + { + case ADDR_SPACE_GENERIC: + return Pmode; + case ADDR_SPACE_EA: + return EAmode; + default: + gcc_unreachable (); + } +} + +/* Determine if one named address space is a subset of another. */ + +static bool +spu_addr_space_subset_p (addr_space_t subset, addr_space_t superset) +{ + gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_EA); + gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_EA); + + if (subset == superset) + return true; + + /* If we have -mno-address-space-conversion, treat __ea and generic as not + being subsets but instead as disjoint address spaces. */ + else if (!TARGET_ADDRESS_SPACE_CONVERSION) + return false; + + else + return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_EA); +} + +/* Convert from one address space to another. */ +static rtx +spu_addr_space_convert (rtx op, tree from_type, tree to_type) +{ + addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type)); + addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type)); + + gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_EA); + gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_EA); + + if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_EA) + { + rtx result, ls; + + ls = gen_const_mem (DImode, + gen_rtx_SYMBOL_REF (Pmode, "__ea_local_store")); + set_mem_align (ls, 128); + + result = gen_reg_rtx (Pmode); + ls = force_reg (Pmode, convert_modes (Pmode, DImode, ls, 1)); + op = force_reg (Pmode, convert_modes (Pmode, EAmode, op, 1)); + ls = emit_conditional_move (ls, NE, op, const0_rtx, Pmode, + ls, const0_rtx, Pmode, 1); + + emit_insn (gen_subsi3 (result, op, ls)); + + return result; + } + + else if (to_as == ADDR_SPACE_EA && from_as == ADDR_SPACE_GENERIC) + { + rtx result, ls; + + ls = gen_const_mem (DImode, + gen_rtx_SYMBOL_REF (Pmode, "__ea_local_store")); + set_mem_align (ls, 128); + + result = gen_reg_rtx (EAmode); + ls = force_reg (EAmode, convert_modes (EAmode, DImode, ls, 1)); + op = force_reg (Pmode, op); + ls = emit_conditional_move (ls, NE, op, const0_rtx, Pmode, + ls, const0_rtx, EAmode, 1); + op = force_reg (EAmode, convert_modes (EAmode, Pmode, op, 1)); + + if (EAmode == SImode) + emit_insn (gen_addsi3 (result, op, ls)); + else + emit_insn (gen_adddi3 (result, op, ls)); + + return result; + } + + else + gcc_unreachable (); +} + + /* Count the total number of instructions in each pipe and return the maximum, which is used as the Minimum Iteration Interval (MII) in the modulo scheduler. get_pipe() will return -2, -1, 0, or 1. @@ -6519,9 +6984,46 @@ spu_section_type_flags (tree decl, const char *name, int reloc) /* .toe needs to have type @nobits. */ if (strcmp (name, ".toe") == 0) return SECTION_BSS; + /* Don't load _ea into the current address space. */ + if (strcmp (name, "._ea") == 0) + return SECTION_WRITE | SECTION_DEBUG; return default_section_type_flags (decl, name, reloc); } +/* Implement targetm.select_section. */ +static section * +spu_select_section (tree decl, int reloc, unsigned HOST_WIDE_INT align) +{ + /* Variables and constants defined in the __ea address space + go into a special section named "._ea". */ + if (TREE_TYPE (decl) != error_mark_node + && TYPE_ADDR_SPACE (TREE_TYPE (decl)) == ADDR_SPACE_EA) + { + /* We might get called with string constants, but get_named_section + doesn't like them as they are not DECLs. Also, we need to set + flags in that case. */ + if (!DECL_P (decl)) + return get_section ("._ea", SECTION_WRITE | SECTION_DEBUG, NULL); + + return get_named_section (decl, "._ea", reloc); + } + + return default_elf_select_section (decl, reloc, align); +} + +/* Implement targetm.unique_section. */ +static void +spu_unique_section (tree decl, int reloc) +{ + /* We don't support unique section names in the __ea address + space for now. */ + if (TREE_TYPE (decl) != error_mark_node + && TYPE_ADDR_SPACE (TREE_TYPE (decl)) != 0) + return; + + default_unique_section (decl, reloc); +} + /* Generate a constant or register which contains 2^SCALE. We assume the result is valid for MODE. Currently, MODE must be V4SFmode and SCALE must be SImode. */ diff --git a/gcc/config/spu/spu.h b/gcc/config/spu/spu.h index 67011a62126..369e6d76e9d 100644 --- a/gcc/config/spu/spu.h +++ b/gcc/config/spu/spu.h @@ -51,7 +51,7 @@ extern GTY(()) int spu_tune; /* Default target_flags if no switches specified. */ #ifndef TARGET_DEFAULT #define TARGET_DEFAULT (MASK_ERROR_RELOC | MASK_SAFE_DMA | MASK_BRANCH_HINTS \ - | MASK_SAFE_HINTS) + | MASK_SAFE_HINTS | MASK_ADDRESS_SPACE_CONVERSION) #endif @@ -469,6 +469,17 @@ targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \ #define ASM_OUTPUT_LABELREF(FILE, NAME) \ asm_fprintf (FILE, "%U%s", default_strip_name_encoding (NAME)) +#define ASM_OUTPUT_SYMBOL_REF(FILE, X) \ + do \ + { \ + tree decl; \ + assemble_name (FILE, XSTR ((X), 0)); \ + if ((decl = SYMBOL_REF_DECL ((X))) != 0 \ + && TREE_CODE (decl) == VAR_DECL \ + && TYPE_ADDR_SPACE (TREE_TYPE (decl))) \ + fputs ("@ppu", FILE); \ + } while (0) + /* Instruction Output */ #define REGISTER_NAMES \ @@ -590,6 +601,13 @@ targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \ } while (0) +/* Address spaces. */ +#define ADDR_SPACE_EA 1 + +/* Named address space keywords. */ +#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__ea", ADDR_SPACE_EA) + + /* Builtins. */ enum spu_builtin_type diff --git a/gcc/config/spu/spu.opt b/gcc/config/spu/spu.opt index 1589199b60b..4ad7128de51 100644 --- a/gcc/config/spu/spu.opt +++ b/gcc/config/spu/spu.opt @@ -82,3 +82,24 @@ Generate code for given CPU mtune= Target RejectNegative Joined Var(spu_tune_string) Schedule code for given CPU + +mea32 +Target Report RejectNegative Var(spu_ea_model,32) Init(32) +Access variables in 32-bit PPU objects (default) + +mea64 +Target Report RejectNegative Var(spu_ea_model,64) VarExists +Access variables in 64-bit PPU objects + +maddress-space-conversion +Target Report Mask(ADDRESS_SPACE_CONVERSION) +Allow conversions between __ea and generic pointers (default) + +mcache-size= +Target Report RejectNegative Joined UInteger +Size (in KB) of software data cache + +matomic-updates +Target Report +Atomically write back software data cache lines (default) + diff --git a/gcc/config/spu/spu_cache.h b/gcc/config/spu/spu_cache.h new file mode 100644 index 00000000000..66a679be5a0 --- /dev/null +++ b/gcc/config/spu/spu_cache.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2008, 2009 Free Software Foundation, Inc. + + This file is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 3 of the License, or (at your option) + any later version. + + This file is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + Under Section 7 of GPL version 3, you are granted additional + permissions described in the GCC Runtime Library Exception, version + 3.1, as published by the Free Software Foundation. + + You should have received a copy of the GNU General Public License and + a copy of the GCC Runtime Library Exception along with this program; + see the files COPYING3 and COPYING.RUNTIME respectively. If not, see + . */ + +#ifndef _SPU_CACHE_H +#define _SPU_CACHE_H + +void *__cache_fetch_dirty (__ea void *ea, int n_bytes_dirty); +void *__cache_fetch (__ea void *ea); +void __cache_evict (__ea void *ea); +void __cache_flush (void); +void __cache_touch (__ea void *ea); + +#define cache_fetch_dirty(_ea, _n_bytes_dirty) \ + __cache_fetch_dirty(_ea, _n_bytes_dirty) + +#define cache_fetch(_ea) __cache_fetch(_ea) +#define cache_touch(_ea) __cache_touch(_ea) +#define cache_evict(_ea) __cache_evict(_ea) +#define cache_flush() __cache_flush() + +#endif diff --git a/gcc/config/spu/t-spu-elf b/gcc/config/spu/t-spu-elf index 0c9236fa89f..a54ede9fa25 100644 --- a/gcc/config/spu/t-spu-elf +++ b/gcc/config/spu/t-spu-elf @@ -66,14 +66,39 @@ fp-bit.c: $(srcdir)/config/fp-bit.c $(srcdir)/config/spu/t-spu-elf # Don't let CTOR_LIST end up in sdata section. CRTSTUFF_T_CFLAGS = -#MULTILIB_OPTIONS=mlarge-mem/mtest-abi -#MULTILIB_DIRNAMES=large-mem test-abi -#MULTILIB_MATCHES= +# Multi-lib support. +MULTILIB_OPTIONS=mea64 # Neither gcc or newlib seem to have a standard way to generate multiple # crt*.o files. So we don't use the standard crt0.o name anymore. -EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o +EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o libgcc_cachemgr.a libgcc_cachemgr_nonatomic.a \ + libgcc_cache8k.a libgcc_cache16k.a libgcc_cache32k.a libgcc_cache64k.a libgcc_cache128k.a + +$(T)cachemgr.o: $(srcdir)/config/spu/cachemgr.c + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(MULTILIB_CFLAGS) -c $< -o $@ + +# Specialised rule to add a -D flag. +$(T)cachemgr_nonatomic.o: $(srcdir)/config/spu/cachemgr.c + $(GCC_FOR_TARGET) $(LIBGCC2_CFLAGS) $(MULTILIB_CFLAGS) -DNONATOMIC -c $< -o $@ + +$(T)libgcc_%.a: $(T)%.o + $(AR_FOR_TARGET) -rcs $@ $< + +$(T)cache8k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=8 -o $@ -c $< + +$(T)cache16k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=16 -o $@ -c $< + +$(T)cache32k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=32 -o $@ -c $< + +$(T)cache64k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=64 -o $@ -c $< + +$(T)cache128k.o: $(srcdir)/config/spu/cache.S + $(GCC_FOR_TARGET) $(MULTILIB_CFLAGS) -D__CACHE_SIZE__=128 -o $@ -c $< LIBGCC = stmp-multilib INSTALL_LIBGCC = install-multilib diff --git a/gcc/config/stormy16/stormy16.h b/gcc/config/stormy16/stormy16.h index 682f7e6f466..fa97e8becdc 100644 --- a/gcc/config/stormy16/stormy16.h +++ b/gcc/config/stormy16/stormy16.h @@ -522,8 +522,6 @@ enum reg_class #define HAVE_PRE_DECREMENT 1 -#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X) - #define MAX_REGS_PER_ADDRESS 1 #ifdef REG_OK_STRICT diff --git a/gcc/config/vax/linux.h b/gcc/config/vax/linux.h index 1087069adbb..dccbe9cc8ee 100644 --- a/gcc/config/vax/linux.h +++ b/gcc/config/vax/linux.h @@ -21,17 +21,7 @@ along with GCC; see the file COPYING3. If not see #undef TARGET_VERSION #define TARGET_VERSION fprintf (stderr, " (VAX GNU/Linux with ELF)"); -#define TARGET_OS_CPP_BUILTINS() \ - do \ - { \ - LINUX_TARGET_OS_CPP_BUILTINS(); \ - if (flag_pic) \ - { \ - builtin_define ("__PIC__"); \ - builtin_define ("__pic__"); \ - } \ - } \ - while (0) +#define TARGET_OS_CPP_BUILTINS() LINUX_TARGET_OS_CPP_BUILTINS() /* We use GAS, G-float double and want new DI patterns. */ #undef TARGET_DEFAULT diff --git a/gcc/configure b/gcc/configure index a1e28a79e4b..292b3dca631 100755 --- a/gcc/configure +++ b/gcc/configure @@ -741,6 +741,8 @@ ac_subst_vars='LTLIBOBJS LIBOBJS enable_plugin pluginlibs +LIBELFINC +LIBELFLIBS CLOOGINC CLOOGLIBS PPLINC @@ -808,6 +810,7 @@ subdirs slibdir dollar gcc_tooldir +enable_lto MAINT zlibinc zlibdir @@ -1061,7 +1064,9 @@ GMPINC PPLLIBS PPLINC CLOOGLIBS -CLOOGINC' +CLOOGINC +LIBELFLIBS +LIBELFINC' # Initialize some variables set by options. @@ -1799,6 +1804,8 @@ Some influential environment variables: PPLINC How to find PPL include files CLOOGLIBS How to link CLOOG CLOOGINC How to find CLOOG include files + LIBELFLIBS How to link libelf + LIBELFINC How to find libelf 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. @@ -11565,13 +11572,13 @@ if test "${lt_cv_nm_interface+set}" = set; then : else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:11568: $ac_compile\"" >&5) + (eval echo "\"\$as_me:11575: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 - (eval echo "\"\$as_me:11571: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval echo "\"\$as_me:11578: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 - (eval echo "\"\$as_me:11574: output\"" >&5) + (eval echo "\"\$as_me:11581: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" @@ -12776,7 +12783,7 @@ ia64-*-hpux*) ;; *-*-irix6*) # Find out which ABI we are using. - echo '#line 12779 "configure"' > conftest.$ac_ext + echo '#line 12786 "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? @@ -14436,11 +14443,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14439: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14446: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14443: \$? = $ac_status" >&5 + echo "$as_me:14450: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14775,11 +14782,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14778: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14785: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:14782: \$? = $ac_status" >&5 + echo "$as_me:14789: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -14880,11 +14887,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14883: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14890: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14887: \$? = $ac_status" >&5 + echo "$as_me:14894: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -14935,11 +14942,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:14938: $lt_compile\"" >&5) + (eval echo "\"\$as_me:14945: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:14942: \$? = $ac_status" >&5 + echo "$as_me:14949: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -17317,7 +17324,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17320 "configure" +#line 17327 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -17413,7 +17420,7 @@ else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF -#line 17416 "configure" +#line 17423 "configure" #include "confdefs.h" #if HAVE_DLFCN_H @@ -19369,11 +19376,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:19372: $lt_compile\"" >&5) + (eval echo "\"\$as_me:19379: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 - echo "$as_me:19376: \$? = $ac_status" >&5 + echo "$as_me:19383: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. @@ -19468,11 +19475,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:19471: $lt_compile\"" >&5) + (eval echo "\"\$as_me:19478: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:19475: \$? = $ac_status" >&5 + echo "$as_me:19482: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -19520,11 +19527,11 @@ else -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:19523: $lt_compile\"" >&5) + (eval echo "\"\$as_me:19530: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 - echo "$as_me:19527: \$? = $ac_status" >&5 + echo "$as_me:19534: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized @@ -22908,6 +22915,37 @@ if test $gcc_cv_as_ix86_sahf = yes; then $as_echo "#define HAVE_AS_IX86_SAHF 1" >>confdefs.h +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for swap suffix" >&5 +$as_echo_n "checking assembler for swap suffix... " >&6; } +if test "${gcc_cv_as_ix86_swap+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_ix86_swap=no + if test x$gcc_cv_as != x; then + echo 'movl.s %esp, %ebp' > conftest.s + if { ac_try='$gcc_cv_as -o conftest.o conftest.s >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + gcc_cv_as_ix86_swap=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_ix86_swap" >&5 +$as_echo "$gcc_cv_as_ix86_swap" >&6; } +if test $gcc_cv_as_ix86_swap = yes; then + +$as_echo "#define HAVE_AS_IX86_SWAP 1" >>confdefs.h + fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for different section symbol subtraction" >&5 @@ -23506,6 +23544,50 @@ if test $gcc_cv_as_powerpc_lwsync = yes; then $as_echo "#define HAVE_AS_LWSYNC 1" >>confdefs.h +fi + + case $target in + *-*-aix*) conftest_s=' .machine "476" + .csect .text[PR] + dci 0';; + *) conftest_s=' .machine "476" + .text + dci 0';; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for data cache invalidate support" >&5 +$as_echo_n "checking assembler for data cache invalidate support... " >&6; } +if test "${gcc_cv_as_powerpc_dci+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + gcc_cv_as_powerpc_dci=no + if test $in_tree_gas = yes; then + if test $gcc_cv_gas_vers -ge `expr \( \( 9 \* 1000 \) + 99 \) \* 1000 + 0` + then gcc_cv_as_powerpc_dci=yes +fi + elif test x$gcc_cv_as != x; then + echo "$conftest_s" > conftest.s + if { ac_try='$gcc_cv_as -a32 -o conftest.o conftest.s >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } + then + gcc_cv_as_powerpc_dci=yes + else + echo "configure: failed program was" >&5 + cat conftest.s >&5 + fi + rm -f conftest.o conftest.s + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_powerpc_dci" >&5 +$as_echo "$gcc_cv_as_powerpc_dci" >&6; } +if test $gcc_cv_as_powerpc_dci = yes; then + +$as_echo "#define HAVE_AS_DCI 1" >>confdefs.h + fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .gnu_attribute support" >&5 @@ -24760,6 +24842,16 @@ do all_compilers="$all_compilers $compilers" all_outputs="$all_outputs $outputs" all_gtfiles="$all_gtfiles [$subdir] $gtfiles" + case ",$enable_languages," in + *,lto,*) + +$as_echo "#define ENABLE_LTO 1" >>confdefs.h + + enable_lto=yes + + ;; + *) ;; + esac done # Pick up gtfiles for c @@ -24941,6 +25033,14 @@ $as_echo "#define HAVE_cloog 1" >>confdefs.h fi + + +if test "x${LIBELFLIBS}" != "x" ; then + +$as_echo "#define HAVE_libelf 1" >>confdefs.h + +fi + # Check for plugin support # Check whether --enable-plugin was given. if test "${enable_plugin+set}" = set; then : @@ -24988,30 +25088,63 @@ rm -f core conftest.err conftest.$ac_objext \ fi # Check -ldl - LIBS="$LIBS -ldl" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -ldl" >&5 -$as_echo_n "checking for -ldl... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing dlopen" >&5 +$as_echo_n "checking for library containing dlopen... " >&6; } +if test "${ac_cv_search_dlopen+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); int main () { -volatile int f = 0; if (f) dlopen ("dummy", 0); +return dlopen (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; }; have_dl=yes -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } +for ac_lib in '' dl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_dlopen=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - if test x"$have_dl" = x"yes"; then + conftest$ac_exeext + if test "${ac_cv_search_dlopen+set}" = set; then : + break +fi +done +if test "${ac_cv_search_dlopen+set}" = set; then : + +else + ac_cv_search_dlopen=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_dlopen" >&5 +$as_echo "$ac_cv_search_dlopen" >&6; } +ac_res=$ac_cv_search_dlopen +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + if test x"$ac_cv_search_dlopen" = x"-ldl"; then pluginlibs="$pluginlibs -ldl" fi @@ -25039,7 +25172,7 @@ $as_echo "no" >&6; }; have_pic_shared=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext - if test x"$have_pic_shared" != x"yes"; then + if test x"$have_pic_shared" != x"yes" -o x"$ac_cv_search_dlopen" = x"no"; then pluginlibs= enable_plugin=no fi diff --git a/gcc/configure.ac b/gcc/configure.ac index d7597d28341..dd3b7e890d2 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -3047,6 +3047,12 @@ foo: nop [AC_DEFINE(HAVE_AS_IX86_SAHF, 1, [Define if your assembler supports the sahf mnemonic.])]) + gcc_GAS_CHECK_FEATURE([swap suffix], + gcc_cv_as_ix86_swap,,, + [movl.s %esp, %ebp],, + [AC_DEFINE(HAVE_AS_IX86_SWAP, 1, + [Define if your assembler supports the swap suffix.])]) + gcc_GAS_CHECK_FEATURE([different section symbol subtraction], gcc_cv_as_ix86_diff_sect_delta,,, [.section .rodata @@ -3249,6 +3255,21 @@ LCF0: [AC_DEFINE(HAVE_AS_LWSYNC, 1, [Define if your assembler supports LWSYNC instructions.])]) + case $target in + *-*-aix*) conftest_s=' .machine "476" + .csect .text[[PR]] + dci 0';; + *) conftest_s=' .machine "476" + .text + dci 0';; + esac + + gcc_GAS_CHECK_FEATURE([data cache invalidate support], + gcc_cv_as_powerpc_dci, [9,99,0], -a32, + [$conftest_s],, + [AC_DEFINE(HAVE_AS_DCI, 1, + [Define if your assembler supports the DCI/ICI instructions.])]) + gcc_GAS_CHECK_FEATURE([.gnu_attribute support], gcc_cv_as_powerpc_gnu_attribute, [2,18,0],, [.gnu_attribute 4,1],, @@ -4041,6 +4062,14 @@ changequote([,])dnl all_compilers="$all_compilers $compilers" all_outputs="$all_outputs $outputs" all_gtfiles="$all_gtfiles [[$subdir]] $gtfiles" + case ",$enable_languages," in + *,lto,*) + AC_DEFINE(ENABLE_LTO, 1, [Define to enable LTO support.]) + enable_lto=yes + AC_SUBST(enable_lto) + ;; + *) ;; + esac done # Pick up gtfiles for c @@ -4213,6 +4242,12 @@ if test "x${CLOOGLIBS}" != "x" ; then AC_DEFINE(HAVE_cloog, 1, [Define if cloog is in use.]) fi +AC_ARG_VAR(LIBELFLIBS,[How to link libelf]) +AC_ARG_VAR(LIBELFINC,[How to find libelf include files]) +if test "x${LIBELFLIBS}" != "x" ; then + AC_DEFINE(HAVE_libelf, 1, [Define if libelf is in use.]) +fi + # Check for plugin support AC_ARG_ENABLE(plugin, [ --enable-plugin enable plugin support], @@ -4239,14 +4274,8 @@ if test x"$enable_plugin" = x"yes"; then fi # Check -ldl - LIBS="$LIBS -ldl" - AC_MSG_CHECKING([for -ldl]) - AC_TRY_LINK( - [#include ], - [volatile int f = 0; if (f) dlopen ("dummy", 0);], - [AC_MSG_RESULT([yes]); have_dl=yes], - [AC_MSG_RESULT([no])]) - if test x"$have_dl" = x"yes"; then + AC_SEARCH_LIBS([dlopen], [dl]) + if test x"$ac_cv_search_dlopen" = x"-ldl"; then pluginlibs="$pluginlibs -ldl" fi @@ -4257,7 +4286,7 @@ if test x"$enable_plugin" = x"yes"; then [extern int X;],[return X == 0;], [AC_MSG_RESULT([yes]); have_pic_shared=yes], [AC_MSG_RESULT([no]); have_pic_shared=no]) - if test x"$have_pic_shared" != x"yes"; then + if test x"$have_pic_shared" != x"yes" -o x"$ac_cv_search_dlopen" = x"no"; then pluginlibs= enable_plugin=no fi diff --git a/gcc/convert.c b/gcc/convert.c index a833418d273..453f5ed873c 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -54,7 +54,17 @@ convert_to_pointer (tree type, tree expr) { case POINTER_TYPE: case REFERENCE_TYPE: - return fold_build1_loc (loc, NOP_EXPR, type, expr); + { + /* If the pointers point to different address spaces, conversion needs + to be done via a ADDR_SPACE_CONVERT_EXPR instead of a NOP_EXPR. */ + addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (type)); + addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr))); + + if (to_as == from_as) + return fold_build1_loc (loc, NOP_EXPR, type, expr); + else + return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr); + } case INTEGER_TYPE: case ENUMERAL_TYPE: diff --git a/gcc/coretypes.h b/gcc/coretypes.h index 11583fffe44..0b8261fc614 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -69,6 +69,13 @@ struct gimple_seq_node_d; typedef struct gimple_seq_node_d *gimple_seq_node; typedef const struct gimple_seq_node_d *const_gimple_seq_node; +/* Address space number for named address space support. */ +typedef unsigned char addr_space_t; + +/* The value of addr_space_t that represents the generic address space. */ +#define ADDR_SPACE_GENERIC 0 +#define ADDR_SPACE_GENERIC_P(AS) ((AS) == ADDR_SPACE_GENERIC) + /* The major intermediate representations of GCC. */ enum ir_type { IR_GIMPLE, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 91a6ad68e12..b63977b968e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,396 @@ +2009-11-06 Jason Merrill + + PR c++/15946 + * parser.c (cp_parser_check_template_parameters): Don't talk about + specialization at function scope. + (cp_parser_diagnose_invalid_type_name): Handle dependent scope. + (cp_parser_parse_and_diagnose_invalid_type_name): Likewise. + (cp_parser_expression_statement): Suggest typename. + * error.c (dump_decl) [SCOPE_REF]: Print the type here. + (dump_expr) [SCOPE_REF]: Call it. + (dump_type) [UNBOUND_CLASS_TEMPLATE]: Check TFF_UNQUALIFIED_NAME. + * cxx-pretty-print.c (pp_cxx_unqualified_id): Print class template + args. + + PR c++/9381 + * decl2.c (build_memfn_type): Preserve attributes. + (cp_reconstruct_complex_type): Likewise. + (maybe_retrofit_in_chrg): Likewise. + * class.c (adjust_clone_args): Likewise. + * call.c (standard_conversion): Use build_memfn_type. + * pt.c (tsubst): Likewise. + * decl.c (build_ptrmem_type): Likewise + (check_function_type): Preserve attributes. + * tree.c (cp_build_type_attribute_variant): Propagate exception + specs on METHOD_TYPE, too. + (strip_typedefs): Preserve exception specs and attributes. + +2009-11-06 Andrew Pinski + + PR c++/41536 + * optimize.c (maybe_clone_body): Copy DECL_ATTRIBUTES and + DECL_DISREGARD_INLINE_LIMITS also. + +2009-11-06 Jakub Jelinek + + PR c++/41967 + * parser.c (cp_parser_omp_for_loop): After diagnosing not perfectly + nested loop and parsing statements, don't cp_parser_require }, instead + exit the loop if next token is CPP_EOF. + +2009-11-05 Jason Merrill + + PR c++/34180 + * method.c (do_build_copy_constructor): Don't drop cv-quals from + the field type. + + PR c++/7046 + * class.c (finish_struct): Store maximum_field_alignment in + TYPE_PRECISION. + * pt.c (instantiate_class_template): Set maximum_field_alignment. + + PR c++/34870 + * name-lookup.c (arg_assoc_class): Call complete_type. + * pt.c (instantiate_class_template): Call uses_template_parms + instead of dependent_type_p. + + PR c++/41703 + * pt.c (check_undeduced_parms): New subroutine of... + (more_specialized_fn): ...here. Undeduced template parms can make + a template less specialized than another. + +2009-11-04 Jason Merrill + + PR c++/39413 + * search.c (lookup_base): Don't complete_type (base). + + PR c++/35067 + * method.c (use_thunk): Check DECL_WEAK as well as + DECL_ONE_ONLY. + + PR c++/17365, DR 218 + * name-lookup.c (add_function): Ignore non-functions. + +2009-11-03 Jason Merrill + + PR c++/36959 + * decl2.c (cxx_callgraph_analyze_expr): Don't reference a function + just because a static variable in it is needed unless -frepo. + + PR c++/41876 + * parser.c (cp_parser_type_specifier_seq): Rename is_condition to + is_declaration. + (cp_parser_exception_declaration): Pass true. + (cp_parser_omp_for_loop): Likewise. + + PR c++/41927 + * typeck.c (build_x_binary_op): Don't do warn_parentheses + if we're in a SFINAE context. + + PR c++/41815 + * call.c (build_call_a): Strip cv-quals from rvalue result. + + PR c++/40944 + * call.c (initialize_reference): Add complain parm. + * typeck.c (convert_for_initialization): Pass it. + * decl.c (grok_reference_init): Likewise. + * cp-tree.h: Declare it. + + PR c++/40687 + * pt.c (do_auto_deduction): Diagnose inconsistent deduction. + +2009-11-02 Dodji Seketeli + + PR c++/37093 + * pt.c (check_valid_ptrmem_cst_expr): New function. + (convert_nontype_argument): Use it to output an error for + illegal pointer to member expressions used as template arguments. + +2009-11-02 Jason Merrill + + Restrict DR 757 change to C++0x mode. + * decl2.c (mark_used): Check cxx_dialect. + * decl.c (grokfndecl): Do check type linkage in C++98 mode. + (grokvardecl): Likewise. + * pt.c (check_instantiated_arg): Likewise. + +2009-11-02 Jakub Jelinek + + PR c++/41774 + * name-lookup.c (handle_namespace_attrs): Pass 1 as last argument to + push_visibility. + * parser.c (cp_parser_namespace_definition): Pass 1 as argument to + pop_visibility. + * rtti.c (push_abi_namespace): Pass 2 as last argument to + push_visibility. + (pop_abi_namespace): Pass 2 as argument to pop_visibility. + +2009-10-31 Jason Merrill + + * tree.c (cv_unqualified): New fn. + * cp-tree.h: Declare it. + * typeck.c (decay_conversion): Use it instead of TYPE_MAIN_VARIANT. + + * rtti.c (tinfo_name): Fix lengths for private case. + +2009-10-31 Jason Merrill + + PR c++/41754 + * call.c (compare_ics): Avoid bad union use when + comparing two ck_lists. + +2009-10-30 Jerry Quinn + + * mangle.c (mangle_type_string_for_rtti): Reapply 153734. + (needs_fake_anon): Likewise. + (write_name): Likewise. + (write_nested_name): Likewise. + * cp-tree.h (mangle_type_string_for_rtti): Likewise. + (get_anonymous_namespace): Likewise. + * name-lookup.c (get_anonymous_namespace_name): Likewise. + * rtti.c (tinfo_name): Likewise, with +1 in the second + build_string call fixed. + (tinfo_base_init): Likewise. + +2009-10-30 Jason Merrill + + Revert: + * decl.c (cp_fname_init): Correct build_string argument. + +2009-10-30 Jerry Quinn + + * mangle.c (mangle_type_string_for_rtti): Revert 153734. + (needs_fake_anon): Likewise. + (write_name): Likewise. + (write_nested_name): Likewise. + * cp-tree.h (mangle_type_string_for_rtti): Likewise. + (get_anonymous_namespace): Likewise. + * name-lookup.c (get_anonymous_namespace_name): Likewise. + * rtti.c (tinfo_name): Likewise. + (tinfo_base_init): Likewise. + +2009-10-30 Dodji Seketeli + + PR c++/41863 + * pt.c (iterative_hash_template_arg): articifial parms + don't have DECL_PARM_INDEX set. Do not hash it. + +2009-10-28 Jerry Quinn + + * mangle.c (mangle_type_string_for_rtti): Revert r149964. + (needs_fake_anon): Likewise. + (write_name): Likewise. + (write_nested_name): Likewise. + * cp-tree.h (mangle_type_string_for_rtti): Likewise. + (get_anonymous_namespace): Likewise. + * name-lookup.c (get_anonymous_namespace_name): Likewise. + * rtti.c (tinfo_name): Insert '*' in front of private names. + (tinfo_base_init): Use it. + +2009-10-28 Jason Merrill + + Core issue 812, 861 + * name-lookup.c (set_decl_namespace): Deal properly with inline + namespaces. + (qualified_lookup_using_namespace): Overhaul. + * pt.c (print_candidates): Handle getting an OVERLOAD. + +2009-10-28 Jason Merrill + + * decl.c (cp_fname_init): Correct build_string argument. + +2009-10-27 Jason Merrill + + Allow no-capture lambdas to convert to function pointer. + * semantics.c (maybe_add_lambda_conv_op): New. + * parser.c (cp_parser_lambda_expression): Call it. + (cp_parser_lambda_declarator_opt): Make op() static if + no captures. + * mangle.c (write_closure_type_name): Adjust. + * semantics.c (finish_this_expr): Adjust. + * decl.c (grok_op_properties): Allow it. + * call.c (build_user_type_conversion_1): Handle static conversion op. + (build_op_call): And op(). + +2009-10-26 Jakub Jelinek + + PR debug/41828 + * cp-lang.c (cxx_dwarf_name): Return NULL instead of + for anonymous aggregate names. + +2009-10-26 Jason Merrill + + PR c++/38796, Core issue 906 + * cp-tree.h (DECL_DEFAULTED_OUTSIDE_CLASS_P): New. + (DECL_DEFAULTED_IN_CLASS_P): New. + * class.c (user_provided_p): Non-static. + (check_methods): Use it. + (check_bases_and_members): Check defaulted fns. + (defaultable_fn_p): Move and rename to... + * method.c (defaultable_fn_check): ...this. + (defaulted_late_check): New. + * pt.c (tsubst_decl): Call it. + * decl2.c (grokfield): Adjust. + * decl.c (cp_finish_decl): Adjust. + (grok_special_member_properties): Use user_provided_p. + +2009-10-26 Dodji Seketeli + + PR c++/41785 + * pt.c (template_args_equal): Handle comparison of + an ARGUMENT_PACK_SELECT node with the arguments node it selects into. + * cp-tree.def: Fix a typo in the description of TYPE_PACK_EXPANSION. + +2009-10-26 Dodji Seketeli + + PR c++/41020 + * decl.c (decls_match): Use DECL_IS_BUILTIN instead of + DECL_BUILT_IN. + +2009-10-23 Dodji Seketeli + + PR c++/40808 + * mangle.c (write_template_args): Allow mangling of empty template + argument list. Updated function comments. + +2009-10-23 Jason Merrill + + * semantics.c (lambda_expr_this_capture): Use thisify_lambda_field. + + * semantics.c (outer_lambda_capture_p): New fn. + (thisify_lambda_field): Factor out... + (add_default_capture): ...from here. + (finish_id_expression): Use them. + + Core issue 899 + * call.c (add_function_candidate): Only permit explicit conversion + ops if copy ctor was called with a single argument. + + * call.c (initialize_reference): Tweak error message. + +2009-10-21 Jakub Jelinek + + * mangle.c (finish_mangling_get_identifier): Use + obstack_base (mangle_obstack) instead of name_base. + +2009-10-19 Jakub Jelinek + + * parser.c (cp_lexer_print_token, cp_parser_is_string_literal, + cp_parser_string_literal, cp_parser_primary_expression): Likewise. + (cp_lexer_get_preprocessor_token): Use C_LEX_STRING_JOIN instead + of C_LEX_RAW_STRINGS. + +2009-10-15 Jason Merrill + + PR c++/38888 + * error.c (dump_template_bindings): Wrap argument packs in {}. + + PR c++/38798 + * parser.c (CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS): New. + (cp_parser_type_specifier): Don't try to parse a class-specifier + or enum-specifier in that case. + (cp_parser_trailing_type_id): New. + (cp_parser_late_return_type_opt): Call it. + (cp_parser_type_id_1): Add is_trailing_return parm. + (cp_parser_type_specifier_seq): Likewise. + +2009-10-14 Jason Merrill + + PR c++/39866 + * call.c (print_z_candidates): Don't print deleted candidates. + (print_z_candidate): Note deleted candidates. + +2009-10-14 Larry Evans + + PR c++/40092 + * tree.c (cp_tree_equal): Add test for TEMPLATE_PARM_PARAMETER_PACK + equality. + +2009-10-12 Jason Merrill + + PR c++/37875 + * parser.c (cp_parser_decltype): Set greater_than_is_operator_p. + + PR c++/37766 + * pt.c (type_unification_real): Call convert_template_argument + for function default template arguments. + (check_default_tmpl_args): Suggest -std=c++0x when function default + template args seen in C++98 mode. + +2009-10-11 Jason Merrill + + PR c++/37204 + * typeck.c (build_reinterpret_cast_1): Handle rvalue refs + properly. + +2009-10-11 Richard Guenther + + * tree.c (cp_free_lang_data): Drop anonymous aggregate names. + +2009-10-08 Jason Merrill + + PR c++/36816 + * pt.c (maybe_adjust_types_for_deduction): Do rvalue ref adjustment + even when DEDUCE_EXACT. + + PR c++/37177 + * pt.c (resolve_nondeduced_context): New. + * cvt.c (convert_to_void): Call it. + * semantics.c (finish_decltype_type): Likewise. + * typeck.c (decay_conversion): Here too. + * pt.c (tsubst_decl): Don't clobber input_location. + Don't register a bad specialization. + +2009-10-07 Gabriel Dos Reis + + * cp-tree.h: Fix location of documentation for DECL_LANG_FLAG_7. + +2009-10-07 Jason Merrill + + PR c++/39863 + * pt.c (tsubst_pack_expansion): Don't do anything now if we + have incomplete packs of different lengths. + + PR c++/41038 + * tree.c (build_qualified_name): Call convert_from_reference. + +2009-10-06 Jason Merrill + + Fix lookup of initialized captures in unevaluated context. + * cp-tree.h (DECL_NORMAL_CAPTURE_P): New. + * name-lookup.c (qualify_lookup): Check it. + * parser.c (cp_parser_lambda_introducer): Pass explicit_init_p + to add_capture. + * semantics.c (add_capture): Set DECL_NORMAL_CAPTURE_P + on captures without explicit init. + (add_default_capture): Pass explicit_init_p. + + Fix capture by copy of types with explicit copy constructor. + * cp-tree.h (TARGET_EXPR_DIRECT_INIT_P): New. + (DIRECT_INIT_EXPR_P): New. + * typeck.c (convert_for_initialization): Just return if + DIRECT_INIT_EXPR_P. + * semantics.c (build_lambda_object): Use + TARGET_EXPR_DIRECT_INIT_P for normal captures. + +2009-10-05 Jason Merrill + + * parser.c: Mark lambda_scope and lambda_count for PCH. + +2009-10-03 Jason Merrill + + PR c++/41553 + * parser.c (cp_parser_lambda_introducer): Avoid infinite loop on + parse error. + +2009-10-02 Jason Merrill + + * mangle.c (write_unnamed_type_name): Implement. + (local_class_index): Split out from... + (discriminator_for_local_entity): ...here. + (nested_anon_class_index): New. + * cp-tree.h (TYPE_FUNCTION_SCOPE_P): New. + 2009-10-02 Janis Johnson * call.c (convert_arg_to_ellipsis): Avoid promoting decimal32 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 3fc22f2b911..1aebaac8cd5 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -313,6 +313,9 @@ build_call_a (tree function, int n, tree *argarray) gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE || TREE_CODE (fntype) == METHOD_TYPE); result_type = TREE_TYPE (fntype); + /* An rvalue has no cv-qualifiers. */ + if (SCALAR_TYPE_P (result_type) || VOID_TYPE_P (result_type)) + result_type = cv_unqualified (result_type); if (TREE_CODE (function) == ADDR_EXPR && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) @@ -893,10 +896,7 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, || cp_type_quals (fbase) != cp_type_quals (tbase)) return NULL; - from = cp_build_qualified_type (tbase, cp_type_quals (fbase)); - from = build_method_type_directly (from, - TREE_TYPE (fromfn), - TREE_CHAIN (TYPE_ARG_TYPES (fromfn))); + from = build_memfn_type (fromfn, tbase, cp_type_quals (tbase)); from = build_ptrmemfunc_type (build_pointer_type (from)); conv = build_conv (ck_pmem, from, conv); conv->base_p = true; @@ -1631,7 +1631,8 @@ add_function_candidate (struct z_candidate **candidates, parmtype = build_pointer_type (parmtype); } - if (ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn)) + if (ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn) + && (len-skip == 1)) { /* Hack: Direct-initialize copy parm (i.e. suppress LOOKUP_ONLYCONVERTING) to make explicit conversion ops @@ -2718,6 +2719,8 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate) inform (input_location, "%s %T ", msgstr, candidate->fn); else if (candidate->viable == -1) inform (input_location, "%s %+#D ", msgstr, candidate->fn); + else if (DECL_DELETED_FN (candidate->fn)) + inform (input_location, "%s %+#D ", msgstr, candidate->fn); else inform (input_location, "%s %+#D", msgstr, candidate->fn); } @@ -2729,6 +2732,23 @@ print_z_candidates (struct z_candidate *candidates) struct z_candidate *cand1; struct z_candidate **cand2; + if (!candidates) + return; + + /* Remove deleted candidates. */ + cand1 = candidates; + for (cand2 = &cand1; *cand2; ) + { + if (TREE_CODE ((*cand2)->fn) == FUNCTION_DECL + && DECL_DELETED_FN ((*cand2)->fn)) + *cand2 = (*cand2)->next; + else + cand2 = &(*cand2)->next; + } + /* ...if there are any non-deleted ones. */ + if (cand1) + candidates = cand1; + /* There may be duplicates in the set of candidates. We put off checking this condition as long as possible, since we have no way to eliminate duplicates from a set of functions in less than n^2 @@ -2751,9 +2771,6 @@ print_z_candidates (struct z_candidate *candidates) } } - if (!candidates) - return; - str = _("candidates are:"); print_z_candidate (str, candidates); if (candidates->next) @@ -2936,11 +2953,16 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) for (fns = TREE_VALUE (conv_fns); fns; fns = OVL_NEXT (fns)) { tree fn = OVL_CURRENT (fns); + tree first = first_arg; if (DECL_NONCONVERTING_P (fn) && (flags & LOOKUP_ONLYCONVERTING)) continue; + /* Lambdas have a static conversion op. */ + if (DECL_STATIC_FUNCTION_P (fn)) + first = NULL_TREE; + /* [over.match.funcs] For conversion functions, the function is considered to be a member of the class of the implicit object argument for the purpose of defining the type of @@ -2951,14 +2973,14 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) if (TREE_CODE (fn) == TEMPLATE_DECL) cand = add_template_candidate (&candidates, fn, fromtype, NULL_TREE, - first_arg, NULL, totype, + first, NULL, totype, TYPE_BINFO (fromtype), conversion_path, flags, DEDUCE_CONV); else cand = add_function_candidate (&candidates, fn, fromtype, - first_arg, NULL, + first, NULL, TYPE_BINFO (fromtype), conversion_path, flags); @@ -3365,20 +3387,30 @@ build_op_call (tree obj, VEC(tree,gc) **args, tsubst_flags_t complain) for (fns = BASELINK_FUNCTIONS (fns); fns; fns = OVL_NEXT (fns)) { tree fn = OVL_CURRENT (fns); + + tree lfirst = first_mem_arg; + if (DECL_STATIC_FUNCTION_P (fn)) + lfirst = NULL_TREE; + if (TREE_CODE (fn) == TEMPLATE_DECL) add_template_candidate (&candidates, fn, base, NULL_TREE, - first_mem_arg, *args, NULL_TREE, + lfirst, *args, NULL_TREE, TYPE_BINFO (type), TYPE_BINFO (type), LOOKUP_NORMAL, DEDUCE_CALL); else add_function_candidate - (&candidates, fn, base, first_mem_arg, *args, TYPE_BINFO (type), + (&candidates, fn, base, lfirst, *args, TYPE_BINFO (type), TYPE_BINFO (type), LOOKUP_NORMAL); } } - convs = lookup_conversions (type); + /* Rather than mess with handling static conversion ops here, just don't + look at conversions in lambdas. */ + if (LAMBDA_TYPE_P (type)) + convs = NULL_TREE; + else + convs = lookup_conversions (type); for (; convs; convs = TREE_CHAIN (convs)) { @@ -6585,8 +6617,9 @@ compare_ics (conversion *ics1, conversion *ics2) /* We couldn't make up our minds; try to figure it out below. */ } - if (ics1->ellipsis_p) - /* Both conversions are ellipsis conversions. */ + if (ics1->ellipsis_p || ics1->kind == ck_list) + /* Both conversions are ellipsis conversions or both are building a + std::initializer_list. */ return 0; /* User-defined conversion sequence U1 is a better conversion sequence @@ -7584,7 +7617,8 @@ set_up_extended_ref_temp (tree decl, tree expr, tree *cleanup, tree *initp) Return the converted expression. */ tree -initialize_reference (tree type, tree expr, tree decl, tree *cleanup) +initialize_reference (tree type, tree expr, tree decl, tree *cleanup, + tsubst_flags_t complain) { conversion *conv; void *p; @@ -7599,16 +7633,19 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup) LOOKUP_NORMAL); if (!conv || conv->bad_p) { - if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST) - && !TYPE_REF_IS_RVALUE (type) - && !real_lvalue_p (expr)) - error ("invalid initialization of non-const reference of " - "type %qT from a temporary of type %qT", - type, TREE_TYPE (expr)); - else - error ("invalid initialization of reference of type " - "%qT from expression of type %qT", type, - TREE_TYPE (expr)); + if (complain & tf_error) + { + if (!(TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST) + && !TYPE_REF_IS_RVALUE (type) + && !real_lvalue_p (expr)) + error ("invalid initialization of non-const reference of " + "type %qT from an rvalue of type %qT", + type, TREE_TYPE (expr)); + else + error ("invalid initialization of reference of type " + "%qT from expression of type %qT", type, + TREE_TYPE (expr)); + } return error_mark_node; } diff --git a/gcc/cp/class.c b/gcc/cp/class.c index d29d6615f33..c798ba2833f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -2677,7 +2677,8 @@ add_implicitly_declared_members (tree t, CLASSTYPE_LAZY_COPY_CTOR (t) = 1; } - /* Currently only lambdas get a lazy move ctor. */ + /* Currently only lambdas get a lazy move ctor, but N2987 adds them for + other classes. */ if (LAMBDA_TYPE_P (t)) CLASSTYPE_LAZY_MOVE_CTOR (t) = 1; @@ -3843,7 +3844,7 @@ check_methods (tree t) VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x); } /* All user-provided destructors are non-trivial. */ - if (DECL_DESTRUCTOR_P (x) && !DECL_DEFAULTED_FN (x)) + if (DECL_DESTRUCTOR_P (x) && user_provided_p (x)) TYPE_HAS_NONTRIVIAL_DESTRUCTOR (t) = 1; } } @@ -4103,6 +4104,7 @@ adjust_clone_args (tree decl) /* A default parameter has been added. Adjust the clone's parameters. */ tree exceptions = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (clone)); + tree attrs = TYPE_ATTRIBUTES (TREE_TYPE (clone)); tree basetype = TYPE_METHOD_BASETYPE (TREE_TYPE (clone)); tree type; @@ -4120,6 +4122,8 @@ adjust_clone_args (tree decl) clone_parms); if (exceptions) type = build_exception_variant (type, exceptions); + if (attrs) + type = cp_build_type_attribute_variant (type, attrs); TREE_TYPE (clone) = type; clone_parms = NULL_TREE; @@ -4174,17 +4178,17 @@ type_has_user_nondefault_constructor (tree t) } /* Returns true iff FN is a user-provided function, i.e. user-declared - and not defaulted at its first declaration. */ + and not defaulted at its first declaration; or explicit, private, + protected, or non-const. */ -static bool +bool user_provided_p (tree fn) { if (TREE_CODE (fn) == TEMPLATE_DECL) return true; else return (!DECL_ARTIFICIAL (fn) - && !(DECL_DEFAULTED_FN (fn) - && DECL_INITIALIZED_IN_CLASS_P (fn))); + && !DECL_DEFAULTED_IN_CLASS_P (fn)); } /* Returns true iff class T has a user-provided constructor. */ @@ -4238,31 +4242,6 @@ type_has_user_provided_default_constructor (tree t) return false; } -/* Returns true if FN can be explicitly defaulted. */ - -bool -defaultable_fn_p (tree fn) -{ - if (DECL_CONSTRUCTOR_P (fn)) - { - if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node) - return true; - else if (copy_fn_p (fn) > 0 - && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn)) - == void_list_node)) - return true; - else - return false; - } - else if (DECL_DESTRUCTOR_P (fn)) - return true; - else if (DECL_ASSIGNMENT_OPERATOR_P (fn) - && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR) - return copy_fn_p (fn); - else - return false; -} - /* Remove all zero-width bit-fields from T. */ static void @@ -4356,6 +4335,7 @@ check_bases_and_members (tree t) tree access_decls; bool saved_complex_asn_ref; bool saved_nontrivial_dtor; + tree fn; /* By default, we use const reference arguments and generate default constructors. */ @@ -4453,6 +4433,31 @@ check_bases_and_members (tree t) cant_have_const_ctor, no_const_asn_ref); + /* Check defaulted declarations here so we have cant_have_const_ctor + and don't need to worry about clones. */ + for (fn = TYPE_METHODS (t); fn; fn = TREE_CHAIN (fn)) + if (DECL_DEFAULTED_IN_CLASS_P (fn)) + { + int copy = copy_fn_p (fn); + if (copy > 0) + { + bool imp_const_p + = (DECL_CONSTRUCTOR_P (fn) ? !cant_have_const_ctor + : !no_const_asn_ref); + bool fn_const_p = (copy == 2); + + if (fn_const_p && !imp_const_p) + /* If the function is defaulted outside the class, we just + give the synthesis error. */ + error ("%q+D declared to take const reference, but implicit " + "declaration would take non-const", fn); + else if (imp_const_p && !fn_const_p) + error ("%q+D declared to take non-const reference cannot be " + "defaulted in the class body", fn); + } + defaulted_late_check (fn); + } + if (LAMBDA_TYPE_P (t)) { /* "The closure type associated with a lambda-expression has a deleted @@ -5514,6 +5519,9 @@ finish_struct (tree t, tree attributes) if (DECL_PURE_VIRTUAL_P (x)) VEC_safe_push (tree, gc, CLASSTYPE_PURE_VIRTUALS (t), x); complete_vars (t); + + /* Remember current #pragma pack value. */ + TYPE_PRECISION (t) = maximum_field_alignment; } else finish_struct_1 (t); diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index d84325d291b..8aa01e24d39 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -137,6 +137,9 @@ cxx_dwarf_name (tree t, int verbosity) { gcc_assert (DECL_P (t)); + if (DECL_NAME (t) + && (ANON_AGGRNAME_P (DECL_NAME (t)) || LAMBDANAME_P (DECL_NAME (t)))) + return NULL; if (verbosity >= 2) return decl_as_string (t, TFF_DECL_SPECIFIERS | TFF_UNQUALIFIED_NAME diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 4df01a8e205..28ecc5bf681 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -393,7 +393,7 @@ DEFTREECODE (NONTYPE_ARGUMENT_PACK, "nontype_argument_pack", tcc_expression, 1) }; The derivation from tuple contains a TYPE_PACK_EXPANSION for the - template arguments. Its EXPR_PACK_EXPANSION is "Values&" and its + template arguments. Its PACK_EXPANSION_PATTERN is "Values&" and its PACK_EXPANSION_PARAMETER_PACKS will contain "Values". */ DEFTREECODE (TYPE_PACK_EXPANSION, "type_pack_expansion", tcc_type, 0) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index fc00176c276..c4b088beb56 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -97,6 +97,7 @@ framework extensions, you must include this file before toplev.h, not after. STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST) TYPENAME_IS_RESOLVING_P (in TYPE_NAME_TYPE) LAMBDA_EXPR_DEDUCE_RETURN_TYPE_P (in LAMBDA_EXPR) + TARGET_EXPR_DIRECT_INIT_P (in TARGET_EXPR) 3: (TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out). ICS_BAD_FLAG (in _CONV) FN_TRY_BLOCK_P (in TRY_BLOCK) @@ -112,8 +113,6 @@ framework extensions, you must include this file before toplev.h, not after. 6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE) DECL_CONSTRUCTION_VTABLE_P (in VAR_DECL) TYPE_MARKED_P (in _TYPE) - 7: DECL_DEAD_FOR_LOCAL (in VAR_DECL) - 8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL) Usage of TYPE_LANG_FLAG_?: 0: TYPE_DEPENDENT_P @@ -147,6 +146,8 @@ framework extensions, you must include this file before toplev.h, not after. DECL_FIELD_IS_BASE (in FIELD_DECL) 7: DECL_DEAD_FOR_LOCAL (in VAR_DECL). DECL_THUNK_P (in a member FUNCTION_DECL) + DECL_NORMAL_CAPTURE_P (in FIELD_DECL) + 8: DECL_DECLARED_CONSTEXPR_P (in VAR_DECL, FUNCTION_DECL) Usage of language-independent fields in a language-dependent manner: @@ -2249,6 +2250,9 @@ struct GTY(()) lang_decl { (DECL_CONTEXT (NODE) \ && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL) +#define TYPE_FUNCTION_SCOPE_P(NODE) \ + (TYPE_CONTEXT (NODE) && TREE_CODE (TYPE_CONTEXT (NODE)) == FUNCTION_DECL) + /* 1 iff VAR_DECL node NODE is a type-info decl. This flag is set for both the primary typeinfo object and the associated NTBS name. */ #define DECL_TINFO_P(NODE) TREE_LANG_FLAG_4 (VAR_DECL_CHECK (NODE)) @@ -2811,10 +2815,18 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_DELETED_FN(DECL) \ (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (DECL))->u.base.threadprivate_or_deleted_p) -/* Nonzero if DECL was declared with '= default'. */ +/* Nonzero if DECL was declared with '= default' (maybe implicitly). */ #define DECL_DEFAULTED_FN(DECL) \ (LANG_DECL_FN_CHECK (DECL)->defaulted_p) +/* Nonzero if DECL is explicitly defaulted in the class body. */ +#define DECL_DEFAULTED_IN_CLASS_P(DECL) \ + (DECL_DEFAULTED_FN (DECL) && DECL_INITIALIZED_IN_CLASS_P (DECL)) +/* Nonzero if DECL was defaulted outside the class body. */ +#define DECL_DEFAULTED_OUTSIDE_CLASS_P(DECL) \ + (DECL_DEFAULTED_FN (DECL) \ + && !(DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL))) + /* Record whether a typedef for type `int' was actually `signed int'. */ #define C_TYPEDEF_EXPLICITLY_SIGNED(EXP) DECL_LANG_FLAG_1 (EXP) @@ -3196,6 +3208,12 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define DECL_FIELD_IS_BASE(NODE) \ DECL_LANG_FLAG_6 (FIELD_DECL_CHECK (NODE)) +/* Nonzero for FIELD_DECL node means that this field is a simple (no + explicit initializer) lambda capture field, making it invisible to + name lookup in unevaluated contexts. */ +#define DECL_NORMAL_CAPTURE_P(NODE) \ + DECL_LANG_FLAG_7 (FIELD_DECL_CHECK (NODE)) + /* Nonzero if TYPE is an anonymous union or struct type. We have to use a flag for this because "A union for which objects or pointers are declared is not an anonymous union" [class.union]. */ @@ -3630,6 +3648,16 @@ more_aggr_init_expr_args_p (const aggr_init_expr_arg_iterator *iter) #define TARGET_EXPR_LIST_INIT_P(NODE) \ TREE_LANG_FLAG_1 (TARGET_EXPR_CHECK (NODE)) +/* True if this TARGET_EXPR expresses direct-initialization of an object + to be named later. */ +#define TARGET_EXPR_DIRECT_INIT_P(NODE) \ + TREE_LANG_FLAG_2 (TARGET_EXPR_CHECK (NODE)) + +/* True if EXPR expresses direct-initialization of a TYPE. */ +#define DIRECT_INIT_EXPR_P(TYPE,EXPR) \ + (TREE_CODE (EXPR) == TARGET_EXPR && TREE_LANG_FLAG_2 (EXPR) \ + && same_type_ignoring_top_level_qualifiers_p (TYPE, TREE_TYPE (EXPR))) + /* An enumeration of the kind of tags that C++ accepts. */ enum tag_types { none_type = 0, /* Not a tag type. */ @@ -4401,7 +4429,7 @@ extern tree type_passed_as (tree); extern tree convert_for_arg_passing (tree, tree); extern bool is_properly_derived_from (tree, tree); extern tree set_up_extended_ref_temp (tree, tree, tree *, tree *); -extern tree initialize_reference (tree, tree, tree, tree *); +extern tree initialize_reference (tree, tree, tree, tree *, tsubst_flags_t); extern tree make_temporary_var_for_ref_to_temp (tree, tree); extern tree strip_top_quals (tree); extern bool reference_related_p (tree, tree); @@ -4463,9 +4491,11 @@ extern void check_for_override (tree, tree); extern void push_class_stack (void); extern void pop_class_stack (void); extern bool type_has_user_nondefault_constructor (tree); +extern bool user_provided_p (tree); extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_default_constructor (tree); -extern bool defaultable_fn_p (tree); +extern void defaulted_late_check (tree); +extern bool defaultable_fn_check (tree); extern void fixup_type_variants (tree); extern tree* decl_cloned_function_p (const_tree, bool); extern void clone_function_decl (tree, int); @@ -4487,7 +4517,6 @@ extern tree type_promotes_to (tree); extern tree perform_qualification_conversions (tree, tree); /* in name-lookup.c */ -extern tree get_anonymous_namespace_name (void); extern tree pushdecl (tree); extern tree pushdecl_maybe_friend (tree, bool); extern void maybe_push_cleanup_level (tree); @@ -4825,7 +4854,9 @@ bool template_template_parameter_p (const_tree); extern tree get_primary_template_innermost_parameters (const_tree); extern tree get_template_innermost_arguments (const_tree); extern tree get_template_argument_pack_elems (const_tree); -extern tree get_function_template_decl (const_tree); +extern tree get_function_template_decl (const_tree); +extern tree resolve_nondeduced_context (tree); + /* in repo.c */ extern void init_repo (void); extern int repo_emit_p (tree); @@ -5038,9 +5069,10 @@ extern tree lambda_capture_field_type (tree); extern tree lambda_return_type (tree); extern tree lambda_function (tree); extern void apply_lambda_return_type (tree, tree); -extern tree add_capture (tree, tree, tree, bool); +extern tree add_capture (tree, tree, tree, bool, bool); extern tree add_default_capture (tree, tree, tree); extern tree lambda_expr_this_capture (tree); +extern void maybe_add_lambda_conv_op (tree); /* in tree.c */ void cp_free_lang_data (tree t); @@ -5114,6 +5146,7 @@ extern tree move (tree); extern tree cp_build_qualified_type_real (tree, int, tsubst_flags_t); #define cp_build_qualified_type(TYPE, QUALS) \ cp_build_qualified_type_real ((TYPE), (QUALS), tf_warning_or_error) +extern tree cv_unqualified (tree); extern special_function_kind special_function_p (const_tree); extern int count_trees (tree); extern int char_type_p (tree); @@ -5266,7 +5299,7 @@ extern tree merge_exception_specifiers (tree, tree); /* in mangle.c */ extern void init_mangle (void); extern void mangle_decl (tree); -extern const char *mangle_type_string_for_rtti (tree); +extern const char *mangle_type_string (tree); extern tree mangle_typeinfo_for_type (tree); extern tree mangle_typeinfo_string_for_type (tree); extern tree mangle_vtbl_for_type (tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index aff002dc666..8c5b001dd15 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -956,6 +956,7 @@ convert_to_void (tree expr, const char *implicit, tsubst_flags_t complain) default:; } + expr = resolve_nondeduced_context (expr); { tree probe = expr; diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 1d7f9cf2caf..4851af901f7 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -200,6 +200,12 @@ pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t) case TYPENAME_TYPE: case UNBOUND_CLASS_TEMPLATE: pp_cxx_unqualified_id (pp, TYPE_NAME (t)); + if (CLASS_TYPE_P (t) && CLASSTYPE_USE_TEMPLATE (t)) + { + pp_cxx_begin_template_argument_list (pp); + pp_cxx_template_argument_list (pp, CLASSTYPE_TI_ARGS (t)); + pp_cxx_end_template_argument_list (pp); + } break; case BIT_NOT_EXPR: diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5eb389fe7e3..5e2f85fd9d4 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -935,7 +935,7 @@ decls_match (tree newdecl, tree olddecl) #ifdef NO_IMPLICIT_EXTERN_C /* A new declaration doesn't match a built-in one unless it is also extern "C". */ - if (DECL_BUILT_IN (olddecl) + if (DECL_IS_BUILTIN (olddecl) && DECL_EXTERN_C_P (olddecl) && !DECL_EXTERN_C_P (newdecl)) return 0; #endif @@ -4390,7 +4390,7 @@ grok_reference_init (tree decl, tree type, tree init, tree *cleanup) DECL_INITIAL for local references (instead assigning to them explicitly); we need to allow the temporary to be initialized first. */ - tmp = initialize_reference (type, init, decl, cleanup); + tmp = initialize_reference (type, init, decl, cleanup, tf_warning_or_error); if (tmp == error_mark_node) return NULL_TREE; @@ -5603,17 +5603,10 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, } else if (init == ridpointers[(int)RID_DEFAULT]) { - if (!defaultable_fn_p (decl)) - { - error ("%qD cannot be defaulted", decl); - DECL_INITIAL (decl) = NULL_TREE; - } + if (defaultable_fn_check (decl)) + DECL_DEFAULTED_FN (decl) = 1; else - { - DECL_DEFAULTED_FN (decl) = 1; - FOR_EACH_CLONE (clone, decl) - DECL_DEFAULTED_FN (clone) = 1; - } + DECL_INITIAL (decl) = NULL_TREE; } } @@ -6775,6 +6768,36 @@ grokfndecl (tree ctype, || decl_function_context (TYPE_MAIN_DECL (ctype)))) publicp = 0; + if (publicp && cxx_dialect == cxx98) + { + /* [basic.link]: A name with no linkage (notably, the name of a class + or enumeration declared in a local scope) shall not be used to + declare an entity with linkage. + + DR 757 relaxes this restriction for C++0x. */ + t = no_linkage_check (TREE_TYPE (decl), + /*relaxed_p=*/false); + if (t) + { + if (TYPE_ANONYMOUS_P (t)) + { + if (DECL_EXTERN_C_P (decl)) + /* Allow this; it's pretty common in C. */; + else + { + permerror (input_location, "non-local function %q#D uses anonymous type", + decl); + if (DECL_ORIGINAL_TYPE (TYPE_NAME (t))) + permerror (input_location, "%q+#D does not refer to the unqualified " + "type, so it is not used for linkage", + TYPE_NAME (t)); + } + } + else + permerror (input_location, "non-local function %q#D uses local type %qT", decl, t); + } + } + TREE_PUBLIC (decl) = publicp; if (! publicp) { @@ -7014,15 +7037,48 @@ grokvardecl (tree type, if (declspecs->specs[(int)ds_thread]) DECL_TLS_MODEL (decl) = decl_default_tls_model (decl); + /* If the type of the decl has no linkage, make sure that we'll + notice that in mark_used. */ + if (cxx_dialect > cxx98 + && decl_linkage (decl) != lk_none + && DECL_LANG_SPECIFIC (decl) == NULL + && !DECL_EXTERN_C_P (decl) + && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)) + retrofit_lang_decl (decl); + if (TREE_PUBLIC (decl)) { - /* If the type of the decl has no linkage, make sure that we'll - notice that in mark_used. */ - if (DECL_LANG_SPECIFIC (decl) == NULL - && TREE_PUBLIC (decl) - && !DECL_EXTERN_C_P (decl) - && no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)) - retrofit_lang_decl (decl); + /* [basic.link]: A name with no linkage (notably, the name of a class + or enumeration declared in a local scope) shall not be used to + declare an entity with linkage. + + DR 757 relaxes this restriction for C++0x. */ + tree t = (cxx_dialect > cxx98 ? NULL_TREE + : no_linkage_check (TREE_TYPE (decl), /*relaxed_p=*/false)); + if (t) + { + if (TYPE_ANONYMOUS_P (t)) + { + if (DECL_EXTERN_C_P (decl)) + /* Allow this; it's pretty common in C. */ + ; + else + { + /* DRs 132, 319 and 389 seem to indicate types with + no linkage can only be used to declare extern "C" + entities. Since it's not always an error in the + ISO C++ 90 Standard, we only issue a warning. */ + warning (0, "non-local variable %q#D uses anonymous type", + decl); + if (DECL_ORIGINAL_TYPE (TYPE_NAME (t))) + warning (0, "%q+#D does not refer to the unqualified " + "type, so it is not used for linkage", + TYPE_NAME (t)); + } + } + else + warning (0, "non-local variable %q#D uses local type %qT", decl, t); + } } else DECL_INTERFACE_KNOWN (decl) = 1; @@ -7114,16 +7170,9 @@ build_ptrmem_type (tree class_type, tree member_type) { if (TREE_CODE (member_type) == METHOD_TYPE) { - tree arg_types; - - arg_types = TYPE_ARG_TYPES (member_type); - class_type = (cp_build_qualified_type - (class_type, - cp_type_quals (TREE_TYPE (TREE_VALUE (arg_types))))); - member_type - = build_method_type_directly (class_type, - TREE_TYPE (member_type), - TREE_CHAIN (arg_types)); + tree arg_types = TYPE_ARG_TYPES (member_type); + cp_cv_quals quals = cp_type_quals (TREE_TYPE (TREE_VALUE (arg_types))); + member_type = build_memfn_type (member_type, class_type, quals); return build_ptrmemfunc_type (build_pointer_type (member_type)); } else @@ -9866,9 +9915,9 @@ grokparms (tree parmlist, tree *parms) 0 if D is not a copy constructor or copy assignment operator. 1 if D is a copy constructor or copy assignment operator whose - first parameter is a reference to const qualified T. - 2 if D is a copy constructor or copy assignment operator whose first parameter is a reference to non-const qualified T. + 2 if D is a copy constructor or copy assignment operator whose + first parameter is a reference to const qualified T. This function can be used as a predicate. Positive values indicate a copy constructor and nonzero values indicate a copy assignment @@ -9977,10 +10026,6 @@ move_fn_p (const_tree d) /* Remember any special properties of member function DECL. */ -#define DECL_DEFAULTED_IN_CLASS_P(DECL) \ - (DECL_DEFAULTED_FN (DECL) \ - && (DECL_ARTIFICIAL (DECL) || DECL_INITIALIZED_IN_CLASS_P (DECL))) - void grok_special_member_properties (tree decl) { @@ -10007,7 +10052,7 @@ grok_special_member_properties (tree decl) are no other parameters or else all other parameters have default arguments. */ TYPE_HAS_INIT_REF (class_type) = 1; - if (!DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_INIT_REF (class_type) = 1; if (ctor > 1) TYPE_HAS_CONST_INIT_REF (class_type) = 1; @@ -10015,8 +10060,7 @@ grok_special_member_properties (tree decl) else if (sufficient_parms_p (FUNCTION_FIRST_USER_PARMTYPE (decl))) { TYPE_HAS_DEFAULT_CONSTRUCTOR (class_type) = 1; - if (TREE_CODE (decl) == TEMPLATE_DECL - || !DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_DFLT (class_type) = 1; } else if (is_list_ctor (decl)) @@ -10035,7 +10079,7 @@ grok_special_member_properties (tree decl) if (assop) { TYPE_HAS_ASSIGN_REF (class_type) = 1; - if (!DECL_DEFAULTED_IN_CLASS_P (decl)) + if (user_provided_p (decl)) TYPE_HAS_COMPLEX_ASSIGN_REF (class_type) = 1; if (assop != 1) TYPE_HAS_CONST_ASSIGN_REF (class_type) = 1; @@ -10221,8 +10265,13 @@ grok_op_properties (tree decl, bool complain) || operator_code == ARRAY_REF || operator_code == NOP_EXPR) { - error ("%qD must be a nonstatic member function", decl); - return false; + if (class_type && LAMBDA_TYPE_P (class_type)) + /* Lambdas can have static op() and conv ops. */; + else + { + error ("%qD must be a nonstatic member function", decl); + return false; + } } else { @@ -11495,7 +11544,7 @@ lookup_enumerator (tree enumtype, tree name) } -/* We're defining DECL. Make sure that it's type is OK. */ +/* We're defining DECL. Make sure that its type is OK. */ static void check_function_type (tree decl, tree current_function_parms) @@ -11529,9 +11578,12 @@ check_function_type (tree decl, tree current_function_parms) TREE_CHAIN (args)); else fntype = build_function_type (void_type_node, args); - TREE_TYPE (decl) + fntype = build_exception_variant (fntype, TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl))); + fntype = (cp_build_type_attribute_variant + (fntype, TYPE_ATTRIBUTES (TREE_TYPE (decl)))); + TREE_TYPE (decl) = fntype; } else abstract_virtuals_error (decl, TREE_TYPE (fntype)); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 3e8c0d7a99c..53f66ad73fc 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -114,20 +114,27 @@ tree build_memfn_type (tree fntype, tree ctype, cp_cv_quals quals) { tree raises; + tree attrs; int type_quals; if (fntype == error_mark_node || ctype == error_mark_node) return error_mark_node; + gcc_assert (TREE_CODE (fntype) == FUNCTION_TYPE + || TREE_CODE (fntype) == METHOD_TYPE); + type_quals = quals & ~TYPE_QUAL_RESTRICT; ctype = cp_build_qualified_type (ctype, type_quals); + raises = TYPE_RAISES_EXCEPTIONS (fntype); + attrs = TYPE_ATTRIBUTES (fntype); fntype = build_method_type_directly (ctype, TREE_TYPE (fntype), (TREE_CODE (fntype) == METHOD_TYPE ? TREE_CHAIN (TYPE_ARG_TYPES (fntype)) : TYPE_ARG_TYPES (fntype))); - raises = TYPE_RAISES_EXCEPTIONS (fntype); if (raises) fntype = build_exception_variant (fntype, raises); + if (attrs) + fntype = cp_build_type_attribute_variant (fntype, attrs); return fntype; } @@ -237,6 +244,9 @@ maybe_retrofit_in_chrg (tree fn) if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) fntype = build_exception_variant (fntype, TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))); + if (TYPE_ATTRIBUTES (TREE_TYPE (fn))) + fntype = (cp_build_type_attribute_variant + (fntype, TYPE_ATTRIBUTES (TREE_TYPE (fn)))); TREE_TYPE (fn) = fntype; /* Now we've got the in-charge parameter. */ @@ -862,9 +872,7 @@ grokfield (const cp_declarator *declarator, } else if (init == ridpointers[(int)RID_DEFAULT]) { - if (!defaultable_fn_p (value)) - error ("%qD cannot be defaulted", value); - else + if (defaultable_fn_check (value)) { DECL_DEFAULTED_FN (value) = 1; DECL_INITIALIZED_IN_CLASS_P (value) = 1; @@ -1221,6 +1229,8 @@ cp_reconstruct_complex_type (tree type, tree bottom) else return bottom; + if (TYPE_ATTRIBUTES (type)) + outer = cp_build_type_attribute_variant (outer, TYPE_ATTRIBUTES (type)); return cp_build_qualified_type (outer, TYPE_QUALS (type)); } @@ -3312,6 +3322,7 @@ cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED) mark_decl_referenced (vtbl); } else if (DECL_CONTEXT (t) + && flag_use_repository && TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL) /* If we need a static variable in a function, then we need the containing function. */ @@ -3992,7 +4003,8 @@ mark_used (tree decl) o the variable or function has extern "C" linkage (7.5 [dcl.link]), or o the variable or function is not used (3.2 [basic.def.odr]) or is defined in the same translation unit. */ - if (decl_linkage (decl) != lk_none + if (cxx_dialect > cxx98 + && decl_linkage (decl) != lk_none && !DECL_EXTERN_C_P (decl) && !DECL_ARTIFICIAL (decl) && !decl_defined_p (decl) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index b50704a3ae4..f4232075119 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -311,7 +311,13 @@ dump_template_bindings (tree parms, tree args, VEC(tree,gc)* typenames) pp_equal (cxx_pp); pp_cxx_whitespace (cxx_pp); if (arg) - dump_template_argument (arg, TFF_PLAIN_IDENTIFIER); + { + if (ARGUMENT_PACK_P (arg)) + pp_cxx_left_brace (cxx_pp); + dump_template_argument (arg, TFF_PLAIN_IDENTIFIER); + if (ARGUMENT_PACK_P (arg)) + pp_cxx_right_brace (cxx_pp); + } else pp_string (cxx_pp, M_("")); @@ -460,8 +466,11 @@ dump_type (tree t, int flags) break; case UNBOUND_CLASS_TEMPLATE: - dump_type (TYPE_CONTEXT (t), flags); - pp_cxx_colon_colon (cxx_pp); + if (! (flags & TFF_UNQUALIFIED_NAME)) + { + dump_type (TYPE_CONTEXT (t), flags); + pp_cxx_colon_colon (cxx_pp); + } pp_cxx_ws_string (cxx_pp, "template"); dump_type (DECL_NAME (TYPE_NAME (t)), flags); break; @@ -941,7 +950,9 @@ dump_decl (tree t, int flags) break; case SCOPE_REF: - pp_expression (cxx_pp, t); + dump_type (TREE_OPERAND (t, 0), flags); + pp_string (cxx_pp, "::"); + dump_decl (TREE_OPERAND (t, 1), flags|TFF_UNQUALIFIED_NAME); break; case ARRAY_REF: @@ -2213,6 +2224,9 @@ dump_expr (tree t, int flags) break; case SCOPE_REF: + dump_decl (t, flags); + break; + case EXPR_PACK_EXPANSION: case TYPEID_EXPR: case MEMBER_REF: diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 1e08465195c..7489665bfa8 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -105,10 +105,6 @@ typedef struct GTY(()) globals { static GTY (()) globals G; -/* Whether or not to pretend that a static function is in an anonymous - namespace. */ -static bool fake_anon_scope; - /* The obstack on which we build mangled names. */ static struct obstack *mangle_obstack; @@ -217,6 +213,7 @@ static void write_discriminator (const int); static void write_local_name (tree, const tree, const tree); static void dump_substitution_candidates (void); static tree mangle_decl_string (const tree); +static int local_class_index (tree); /* Control functions. */ @@ -733,20 +730,6 @@ write_encoding (const tree decl) } } -/* Since we now use strcmp to compare typeinfos on all targets because of - the RTLD_LOCAL problem, we need to munge the typeinfo name used for - local classes of static functions to fix g++.dg/abi/local1.C. We do - that by pretending that the function is in an anonymous namespace. */ - -static bool -needs_fake_anon (const_tree decl) -{ - /* Pretend there's an anonymous namespace right around a static - function if we're mangling for RTTI. */ - return (fake_anon_scope && !TREE_PUBLIC (decl) - && TREE_CODE (decl) == FUNCTION_DECL); -} - /* Lambdas can have a bit more context for mangling, specifically VAR_DECL or PARM_DECL context, which doesn't belong in DECL_CONTEXT. */ @@ -790,18 +773,13 @@ write_name (tree decl, const int ignore_local_scope) context = decl_mangling_context (decl); - gcc_assert (context != NULL_TREE); - - /* If we need a fake anonymous namespace, force the nested name path. */ - if (needs_fake_anon (decl) && context == global_namespace) - context = error_mark_node; - /* A decl in :: or ::std scope is treated specially. The former is mangled using or , the latter with a special substitution. Also, a name that is directly in a local function scope is also mangled with rather than a full . */ - if (context == global_namespace + if (context == NULL + || context == global_namespace || DECL_NAMESPACE_STD_P (context) || (ignore_local_scope && TREE_CODE (context) == FUNCTION_DECL)) { @@ -819,9 +797,6 @@ write_name (tree decl, const int ignore_local_scope) } else { - if (context == error_mark_node) - context = global_namespace; - /* Handle local names, unless we asked not to (that is, invoked under , to handle only the part of the name under the local scope). */ @@ -834,10 +809,10 @@ write_name (tree decl, const int ignore_local_scope) directly in that function's scope, either decl or one of its enclosing scopes. */ tree local_entity = decl; - while (context != global_namespace) + while (context != NULL && context != global_namespace) { /* Make sure we're always dealing with decls. */ - if (TYPE_P (context)) + if (context != NULL && TYPE_P (context)) context = TYPE_NAME (context); /* Is this a function? */ if (TREE_CODE (context) == FUNCTION_DECL @@ -882,6 +857,7 @@ write_unscoped_name (const tree decl) /* If not, it should be either in the global namespace, or directly in a local function scope. */ gcc_assert (context == global_namespace + || context != NULL || TREE_CODE (context) == FUNCTION_DECL); write_unqualified_name (decl); @@ -953,9 +929,6 @@ write_nested_name (const tree decl) { /* No, just use */ write_prefix (DECL_CONTEXT (decl)); - if (needs_fake_anon (decl)) - /* Pretend this static function is in an anonymous namespace. */ - write_source_name (get_anonymous_namespace_name ()); write_unqualified_name (decl); } write_char ('E'); @@ -1204,8 +1177,7 @@ write_unqualified_name (const tree decl) tree type = TREE_TYPE (decl); if (TREE_CODE (decl) == TYPE_DECL - && TYPE_ANONYMOUS_P (type) - && !ANON_UNION_TYPE_P (type)) + && TYPE_ANONYMOUS_P (type)) write_unnamed_type_name (type); else if (TREE_CODE (decl) == TYPE_DECL && LAMBDA_TYPE_P (type)) @@ -1252,14 +1224,48 @@ write_compact_number (int num) write_char ('_'); } +/* Return how many unnamed types precede TYPE in its enclosing class. */ + +static int +nested_anon_class_index (tree type) +{ + int index = 0; + tree member = TYPE_FIELDS (TYPE_CONTEXT (type)); + for (; member; member = TREE_CHAIN (member)) + if (DECL_IMPLICIT_TYPEDEF_P (member)) + { + tree memtype = TREE_TYPE (member); + if (memtype == type) + return index; + else if (TYPE_ANONYMOUS_P (memtype)) + ++index; + } + + gcc_unreachable (); +} + +/* ::= Ut [ ] _ */ + static void write_unnamed_type_name (const tree type __attribute__ ((__unused__))) { + int discriminator; MANGLE_TRACE_TREE ("unnamed-type-name", type); + if (TYPE_FUNCTION_SCOPE_P (type)) + discriminator = local_class_index (type); + else if (TYPE_CLASS_SCOPE_P (type)) + discriminator = nested_anon_class_index (type); + else + { + gcc_assert (no_linkage_check (type, /*relaxed_p=*/true)); + /* Just use the old mangling at namespace scope. */ + write_source_name (TYPE_IDENTIFIER (type)); + return; + } + write_string ("Ut"); - /* TODO: Implement discriminators for unnamed-types. */ - write_char ('_'); + write_compact_number (discriminator); } /* ::= Ul E [ ] _ @@ -1275,7 +1281,7 @@ write_closure_type_name (const tree type) MANGLE_TRACE_TREE ("closure-type-name", type); write_string ("Ul"); - write_method_parms (parms, /*method_p=*/1, fn); + write_method_parms (parms, DECL_NONSTATIC_MEMBER_FUNCTION_P (fn), fn); write_char ('E'); write_compact_number (LAMBDA_EXPR_DISCRIMINATOR (lambda)); } @@ -1539,6 +1545,29 @@ write_special_name_destructor (const tree dtor) } } +/* Scan the vector of local classes and return how many others with the + same name (or same no name) and context precede ENTITY. */ + +static int +local_class_index (tree entity) +{ + int ix, discriminator = 0; + tree name = (TYPE_ANONYMOUS_P (entity) ? NULL_TREE + : TYPE_IDENTIFIER (entity)); + tree ctx = TYPE_CONTEXT (entity); + for (ix = 0; ; ix++) + { + tree type = VEC_index (tree, local_classes, ix); + if (type == entity) + return discriminator; + if (TYPE_CONTEXT (type) == ctx + && (name ? TYPE_IDENTIFIER (type) == name + : TYPE_ANONYMOUS_P (type))) + ++discriminator; + } + gcc_unreachable (); +} + /* Return the discriminator for ENTITY appearing inside FUNCTION. The discriminator is the lexical ordinal of VAR among entities with the same name in the same FUNCTION. */ @@ -1546,15 +1575,17 @@ write_special_name_destructor (const tree dtor) static int discriminator_for_local_entity (tree entity) { - /* Assume this is the only local entity with this name. */ - int discriminator = 0; - - if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity)) - discriminator = DECL_DISCRIMINATOR (entity); + if (DECL_DISCRIMINATOR_P (entity)) + { + if (DECL_LANG_SPECIFIC (entity)) + return DECL_DISCRIMINATOR (entity); + else + /* The first entity with a particular name doesn't get + DECL_LANG_SPECIFIC/DECL_DISCRIMINATOR. */ + return 0; + } else if (TREE_CODE (entity) == TYPE_DECL) { - int ix; - /* Scan the list of local classes. */ entity = TREE_TYPE (entity); @@ -1562,18 +1593,10 @@ discriminator_for_local_entity (tree entity) if (LAMBDA_TYPE_P (entity) || TYPE_ANONYMOUS_P (entity)) return 0; - for (ix = 0; ; ix++) - { - tree type = VEC_index (tree, local_classes, ix); - if (type == entity) - break; - if (TYPE_IDENTIFIER (type) == TYPE_IDENTIFIER (entity) - && TYPE_CONTEXT (type) == TYPE_CONTEXT (entity)) - ++discriminator; - } + return local_class_index (entity); } - - return discriminator; + else + gcc_unreachable (); } /* Return the discriminator for STRING, a string literal used inside @@ -2233,21 +2256,22 @@ write_class_enum_type (const tree type) /* Non-terminal . ARGS is a TREE_VEC of template arguments. - ::= I + E */ + ::= I * E */ static void write_template_args (tree args) { int i; - int length = TREE_VEC_LENGTH (args); + int length = 0; MANGLE_TRACE_TREE ("template-args", args); write_char ('I'); - gcc_assert (length > 0); + if (args) + length = TREE_VEC_LENGTH (args); - if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC) + if (args && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC) { /* We have nested template args. We want the innermost template argument list. */ @@ -2907,7 +2931,7 @@ finish_mangling_get_identifier (const bool warn) finish_mangling_internal (warn); /* Don't obstack_finish here, and the next start_mangling will remove the identifier. */ - return get_identifier ((const char *) name_base); + return get_identifier ((const char *) obstack_base (mangle_obstack)); } /* Initialize data structures for mangling. */ @@ -2960,18 +2984,15 @@ mangle_decl (const tree decl) SET_DECL_ASSEMBLER_NAME (decl, id); } -/* Generate the mangled representation of TYPE for the typeinfo name. */ +/* Generate the mangled representation of TYPE. */ const char * -mangle_type_string_for_rtti (const tree type) +mangle_type_string (const tree type) { const char *result; start_mangling (type); - /* Mangle in a fake anonymous namespace if necessary. */ - fake_anon_scope = true; write_type (type); - fake_anon_scope = false; result = finish_mangling (/*warn=*/false); if (DEBUG_MANGLE) fprintf (stderr, "mangle_type_string = '%s'\n\n", result); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index e8b28d877d7..47f9e424dbd 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -378,7 +378,7 @@ use_thunk (tree thunk_fndecl, bool emit_p) DECL_VISIBILITY (thunk_fndecl) = DECL_VISIBILITY (function); DECL_VISIBILITY_SPECIFIED (thunk_fndecl) = DECL_VISIBILITY_SPECIFIED (function); - if (DECL_ONE_ONLY (function)) + if (DECL_ONE_ONLY (function) || DECL_WEAK (function)) make_decl_one_only (thunk_fndecl, cxx_comdat_group (thunk_fndecl)); if (flag_syntax_only) @@ -622,6 +622,7 @@ do_build_copy_constructor (tree fndecl) if (DECL_MUTABLE_P (field)) quals &= ~TYPE_QUAL_CONST; + quals |= TYPE_QUALS (expr_type); expr_type = cp_build_qualified_type (expr_type, quals); } @@ -1130,6 +1131,88 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) return fn; } +/* Gives any errors about defaulted functions which need to be deferred + until the containing class is complete. */ + +void +defaulted_late_check (tree fn) +{ + /* Complain about invalid signature for defaulted fn. */ + tree ctx = DECL_CONTEXT (fn); + special_function_kind kind = special_function_p (fn); + bool fn_const_p = (copy_fn_p (fn) == 2); + tree implicit_fn = implicitly_declare_fn (kind, ctx, fn_const_p); + + if (!same_type_p (TREE_TYPE (TREE_TYPE (fn)), + TREE_TYPE (TREE_TYPE (implicit_fn))) + || !compparms (TYPE_ARG_TYPES (TREE_TYPE (fn)), + TYPE_ARG_TYPES (TREE_TYPE (implicit_fn)))) + { + error ("defaulted declaration %q+D", fn); + error_at (DECL_SOURCE_LOCATION (fn), + "does not match expected signature %qD", implicit_fn); + } +} + +/* Returns true iff FN can be explicitly defaulted, and gives any + errors if defaulting FN is ill-formed. */ + +bool +defaultable_fn_check (tree fn) +{ + special_function_kind kind = sfk_none; + + if (DECL_CONSTRUCTOR_P (fn)) + { + if (FUNCTION_FIRST_USER_PARMTYPE (fn) == void_list_node) + kind = sfk_constructor; + else if (copy_fn_p (fn) > 0 + && (TREE_CHAIN (FUNCTION_FIRST_USER_PARMTYPE (fn)) + == void_list_node)) + kind = sfk_copy_constructor; + else if (move_fn_p (fn)) + kind = sfk_move_constructor; + } + else if (DECL_DESTRUCTOR_P (fn)) + kind = sfk_destructor; + else if (DECL_ASSIGNMENT_OPERATOR_P (fn) + && DECL_OVERLOADED_OPERATOR_P (fn) == NOP_EXPR + && copy_fn_p (fn)) + kind = sfk_assignment_operator; + + if (kind == sfk_none) + { + error ("%qD cannot be defaulted", fn); + return false; + } + else + { + tree t = FUNCTION_FIRST_USER_PARMTYPE (fn); + for (; t && t != void_list_node; t = TREE_CHAIN (t)) + if (TREE_PURPOSE (t)) + { + error ("defaulted function %q+D with default argument", fn); + break; + } + if (TYPE_BEING_DEFINED (DECL_CONTEXT (fn))) + { + if (DECL_NONCONVERTING_P (fn)) + error ("%qD declared explicit cannot be defaulted in the class " + "body", fn); + if (current_access_specifier != access_public_node) + error ("%qD declared with non-public access cannot be defaulted " + "in the class body", fn); + if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) + error ("function %q+D defaulted on its first declaration " + "must not have an exception-specification", fn); + } + else if (!processing_template_decl) + defaulted_late_check (fn); + + return true; + } +} + /* Add an implicit declaration to TYPE for the kind of function indicated by SFK. Return the FUNCTION_DECL for the new implicit declaration. */ diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 459e7390805..14f97873484 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -62,14 +62,19 @@ static GTY(()) tree anonymous_namespace_name; /* Initialize anonymous_namespace_name if necessary, and return it. */ -tree +static tree get_anonymous_namespace_name (void) { if (!anonymous_namespace_name) { /* The anonymous namespace has to have a unique name if typeinfo objects are being compared by name. */ - anonymous_namespace_name = get_file_function_name ("N"); + if (! flag_weak || ! SUPPORTS_ONE_ONLY) + anonymous_namespace_name = get_file_function_name ("N"); + else + /* The demangler expects anonymous namespaces to be called + something starting with '_GLOBAL__N_'. */ + anonymous_namespace_name = get_identifier ("_GLOBAL__N_1"); } return anonymous_namespace_name; } @@ -3062,7 +3067,7 @@ set_namespace_binding (tree name, tree scope, tree val) void set_decl_namespace (tree decl, tree scope, bool friendp) { - tree old, fn; + tree old; /* Get rid of namespace aliases. */ scope = ORIGINAL_NAMESPACE (scope); @@ -3087,17 +3092,25 @@ set_decl_namespace (tree decl, tree scope, bool friendp) if (old == error_mark_node) /* No old declaration at all. */ goto complain; + /* If it's a TREE_LIST, the result of the lookup was ambiguous. */ + if (TREE_CODE (old) == TREE_LIST) + { + error ("reference to %qD is ambiguous", decl); + print_candidates (old); + return; + } if (!is_overloaded_fn (decl)) - /* Don't compare non-function decls with decls_match here, since - it can't check for the correct constness at this - point. pushdecl will find those errors later. */ - return; + { + /* We might have found OLD in an inline namespace inside SCOPE. */ + DECL_CONTEXT (decl) = DECL_CONTEXT (old); + /* Don't compare non-function decls with decls_match here, since + it can't check for the correct constness at this + point. pushdecl will find those errors later. */ + return; + } /* Since decl is a function, old should contain a function decl. */ if (!is_overloaded_fn (old)) goto complain; - fn = OVL_CURRENT (old); - if (!is_associated_namespace (scope, CP_DECL_CONTEXT (fn))) - goto complain; /* A template can be explicitly specialized in any namespace. */ if (processing_explicit_instantiation) return; @@ -3113,12 +3126,43 @@ set_decl_namespace (tree decl, tree scope, bool friendp) return; if (is_overloaded_fn (old)) { - for (; old; old = OVL_NEXT (old)) - if (decls_match (decl, OVL_CURRENT (old))) + tree found = NULL_TREE; + tree elt = old; + for (; elt; elt = OVL_NEXT (elt)) + { + tree ofn = OVL_CURRENT (elt); + /* Adjust DECL_CONTEXT first so decls_match will return true + if DECL will match a declaration in an inline namespace. */ + DECL_CONTEXT (decl) = DECL_CONTEXT (ofn); + if (decls_match (decl, ofn)) + { + if (found && !decls_match (found, ofn)) + { + DECL_CONTEXT (decl) = FROB_CONTEXT (scope); + error ("reference to %qD is ambiguous", decl); + print_candidates (old); + return; + } + found = ofn; + } + } + if (found) + { + if (!is_associated_namespace (scope, CP_DECL_CONTEXT (found))) + goto complain; + DECL_CONTEXT (decl) = DECL_CONTEXT (found); return; + } } - else if (decls_match (decl, old)) - return; + else + { + DECL_CONTEXT (decl) = DECL_CONTEXT (old); + if (decls_match (decl, old)) + return; + } + + /* It didn't work, go back to the explicit scope. */ + DECL_CONTEXT (decl) = FROB_CONTEXT (scope); complain: error ("%qD should have been declared inside %qD", decl, scope); } @@ -3175,7 +3219,7 @@ handle_namespace_attrs (tree ns, tree attributes) "%qD attribute is meaningless since members of the " "anonymous namespace get local symbols", name); - push_visibility (TREE_STRING_POINTER (x)); + push_visibility (TREE_STRING_POINTER (x), 1); saw_vis = true; } else @@ -3757,10 +3801,9 @@ qualify_lookup (tree val, int flags) return true; if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES)) return false; - /* In unevaluated context, look past capture fields. */ - /* FIXME this will cause trouble with the initializer extension. */ + /* In unevaluated context, look past normal capture fields. */ if (cp_unevaluated_operand && TREE_CODE (val) == FIELD_DECL - && LAMBDA_TYPE_P (DECL_CONTEXT (val))) + && DECL_NORMAL_CAPTURE_P (val)) return false; return true; } @@ -3926,6 +3969,19 @@ lookup_using_namespace (tree name, struct scope_binding *val, POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, val->value != error_mark_node); } +/* Returns true iff VEC contains TARGET. */ + +static bool +tree_vec_contains (VEC(tree,gc)* vec, tree target) +{ + unsigned int i; + tree elt; + for (i = 0; VEC_iterate(tree,vec,i,elt); ++i) + if (elt == target) + return true; + return false; +} + /* [namespace.qual] Accepts the NAME to lookup and its qualifying SCOPE. Returns the name/type pair found into the cxx_binding *RESULT, @@ -3936,62 +3992,72 @@ qualified_lookup_using_namespace (tree name, tree scope, struct scope_binding *result, int flags) { /* Maintain a list of namespaces visited... */ - tree seen = NULL_TREE; + VEC(tree,gc) *seen = NULL; + VEC(tree,gc) *seen_inline = NULL; /* ... and a list of namespace yet to see. */ - tree todo = NULL_TREE; - tree todo_maybe = NULL_TREE; - tree *todo_weak = &todo_maybe; + VEC(tree,gc) *todo = NULL; + VEC(tree,gc) *todo_maybe = NULL; + VEC(tree,gc) *todo_inline = NULL; tree usings; timevar_push (TV_NAME_LOOKUP); /* Look through namespace aliases. */ scope = ORIGINAL_NAMESPACE (scope); - while (scope && result->value != error_mark_node) + + /* Algorithm: Starting with SCOPE, walk through the the set of used + namespaces. For each used namespace, look through its inline + namespace set for any bindings and usings. If no bindings are found, + add any usings seen to the set of used namespaces. */ + VEC_safe_push (tree, gc, todo, scope); + + while (VEC_length (tree, todo)) { - cxx_binding *binding = - cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), name); - seen = tree_cons (scope, NULL_TREE, seen); - if (binding) - ambiguous_decl (result, binding, flags); - - /* Consider strong using directives always, and non-strong ones - if we haven't found a binding yet. */ - for (usings = DECL_NAMESPACE_USING (scope); usings; - usings = TREE_CHAIN (usings)) - /* If this was a real directive, and we have not seen it. */ - if (!TREE_INDIRECT_USING (usings)) - { - /* Try to avoid queuing the same namespace more than once, - the exception being when a namespace was already - enqueued for todo_maybe and then a strong using is - found for it. We could try to remove it from - todo_maybe, but it's probably not worth the effort. */ - if (is_associated_namespace (scope, TREE_PURPOSE (usings)) - && !purpose_member (TREE_PURPOSE (usings), seen) - && !purpose_member (TREE_PURPOSE (usings), todo)) - todo = tree_cons (TREE_PURPOSE (usings), NULL_TREE, todo); - else if (!binding - && !purpose_member (TREE_PURPOSE (usings), seen) - && !purpose_member (TREE_PURPOSE (usings), todo) - && !purpose_member (TREE_PURPOSE (usings), todo_maybe)) - *todo_weak = tree_cons (TREE_PURPOSE (usings), NULL_TREE, - *todo_weak); - } - if (todo) - { - scope = TREE_PURPOSE (todo); - todo = TREE_CHAIN (todo); - } - else if (todo_maybe - && (!result->value && !result->type)) + bool found_here; + scope = VEC_pop (tree, todo); + if (tree_vec_contains (seen, scope)) + continue; + VEC_safe_push (tree, gc, seen, scope); + VEC_safe_push (tree, gc, todo_inline, scope); + + found_here = false; + while (VEC_length (tree, todo_inline)) { - scope = TREE_PURPOSE (todo_maybe); - todo = TREE_CHAIN (todo_maybe); - todo_maybe = NULL_TREE; - todo_weak = &todo; + cxx_binding *binding; + + scope = VEC_pop (tree, todo_inline); + if (tree_vec_contains (seen_inline, scope)) + continue; + VEC_safe_push (tree, gc, seen_inline, scope); + + binding = + cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (scope), name); + if (binding) + { + found_here = true; + ambiguous_decl (result, binding, flags); + } + + for (usings = DECL_NAMESPACE_USING (scope); usings; + usings = TREE_CHAIN (usings)) + if (!TREE_INDIRECT_USING (usings)) + { + if (is_associated_namespace (scope, TREE_PURPOSE (usings))) + VEC_safe_push (tree, gc, todo_inline, TREE_PURPOSE (usings)); + else + VEC_safe_push (tree, gc, todo_maybe, TREE_PURPOSE (usings)); + } } + + if (found_here) + VEC_truncate (tree, todo_maybe, 0); else - scope = NULL_TREE; /* If there never was a todo list. */ + while (VEC_length (tree, todo_maybe)) + VEC_safe_push (tree, gc, todo, VEC_pop (tree, todo_maybe)); } + VEC_free (tree,gc,todo); + VEC_free (tree,gc,todo_maybe); + VEC_free (tree,gc,todo_inline); + VEC_free (tree,gc,seen); + VEC_free (tree,gc,seen_inline); POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, result->value != error_mark_node); } @@ -4499,26 +4565,15 @@ add_function (struct arg_lookup *k, tree fn) total number of functions being compared, which should usually be the case. */ - /* We must find only functions, or exactly one non-function. */ - if (!k->functions) + if (!is_overloaded_fn (fn)) + /* All names except those of (possibly overloaded) functions and + function templates are ignored. */; + else if (!k->functions) k->functions = fn; else if (fn == k->functions) ; - else if (is_overloaded_fn (k->functions) && is_overloaded_fn (fn)) - k->functions = build_overload (fn, k->functions); else - { - tree f1 = OVL_CURRENT (k->functions); - tree f2 = fn; - if (is_overloaded_fn (f1)) - { - fn = f1; f1 = f2; f2 = fn; - } - error ("%q+D is not a function,", f1); - error (" conflict with %q+D", f2); - error (" in call to %qD", k->name); - return true; - } + k->functions = build_overload (fn, k->functions); return false; } @@ -4725,6 +4780,8 @@ arg_assoc_class (struct arg_lookup *k, tree type) if (arg_assoc_namespace (k, context)) return true; + complete_type (type); + if (TYPE_BINFO (type)) { /* Process baseclasses. */ diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 58d5b9001d2..662bd4a22a3 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -199,6 +199,8 @@ maybe_clone_body (tree fn) DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn); DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn); DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn); + DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); + DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn); /* Adjust the parameter names and locations. */ parm = DECL_ARGUMENTS (fn); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 210d3dda0e0..47f5f13f1d3 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -402,7 +402,7 @@ cp_lexer_get_preprocessor_token (cp_lexer *lexer, cp_token *token) /* Get a new token from the preprocessor. */ token->type = c_lex_with_flags (&token->u.value, &token->location, &token->flags, - lexer == NULL ? 0 : C_LEX_RAW_STRINGS); + lexer == NULL ? 0 : C_LEX_STRING_NO_JOIN); token->keyword = RID_MAX; token->pragma_kind = PRAGMA_NONE; @@ -792,6 +792,7 @@ cp_lexer_print_token (FILE * stream, cp_token *token) case CPP_STRING16: case CPP_STRING32: case CPP_WSTRING: + case CPP_UTF8STRING: fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->u.value)); break; @@ -1194,8 +1195,12 @@ enum /* The construct is optional. If it is not present, then no error should be issued. */ CP_PARSER_FLAGS_OPTIONAL = 0x1, - /* When parsing a type-specifier, do not allow user-defined types. */ - CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2 + /* When parsing a type-specifier, treat user-defined type-names + as non-type identifiers. */ + CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2, + /* When parsing a type-specifier, do not try to parse a class-specifier + or enum-specifier. */ + CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS = 0x4 }; /* This type is used for parameters and variables which hold @@ -1741,10 +1746,11 @@ static tree cp_parser_type_id (cp_parser *); static tree cp_parser_template_type_arg (cp_parser *); +static tree cp_parser_trailing_type_id (cp_parser *); static tree cp_parser_type_id_1 - (cp_parser *, bool); + (cp_parser *, bool, bool); static void cp_parser_type_specifier_seq - (cp_parser *, bool, cp_decl_specifier_seq *); + (cp_parser *, bool, bool, cp_decl_specifier_seq *); static tree cp_parser_parameter_declaration_clause (cp_parser *); static tree cp_parser_parameter_declaration_list @@ -2060,7 +2066,8 @@ cp_parser_is_string_literal (cp_token* token) return (token->type == CPP_STRING || token->type == CPP_STRING16 || token->type == CPP_STRING32 || - token->type == CPP_WSTRING); + token->type == CPP_WSTRING || + token->type == CPP_UTF8STRING); } /* Returns nonzero if TOKEN is the indicated KEYWORD. */ @@ -2393,6 +2400,11 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser, if (TREE_CODE (parser->scope) == NAMESPACE_DECL) error_at (location, "%qE in namespace %qE does not name a type", id, parser->scope); + else if (TYPE_P (parser->scope) + && dependent_scope_p (parser->scope)) + error_at (location, "need % before %<%T::%E%> to name " + "a type in dependent scope %qT", + parser->scope, id, parser->scope); else if (TYPE_P (parser->scope)) error_at (location, "%qE in class %qT does not name a type", id, parser->scope); @@ -2426,11 +2438,8 @@ cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser) /*declarator_p=*/true, /*optional_p=*/false); /* After the id-expression, there should be a plain identifier, - otherwise this is not a simple variable declaration. Also, if - the scope is dependent, we cannot do much. */ + otherwise this is not a simple variable declaration. */ if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME) - || (parser->scope && TYPE_P (parser->scope) - && dependent_type_p (parser->scope)) || TREE_CODE (id) == TYPE_DECL) { cp_parser_abort_tentative_parse (parser); @@ -2999,6 +3008,7 @@ cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok) { default: case CPP_STRING: + case CPP_UTF8STRING: TREE_TYPE (value) = char_array_type_node; break; case CPP_STRING16: @@ -3228,6 +3238,7 @@ cp_parser_primary_expression (cp_parser *parser, case CPP_STRING16: case CPP_STRING32: case CPP_WSTRING: + case CPP_UTF8STRING: /* ??? Should wide strings be allowed when parser->translate_strings_p is false (i.e. in attributes)? If not, we can kill the third argument to cp_parser_string_literal. */ @@ -5794,7 +5805,8 @@ cp_parser_new_type_id (cp_parser* parser, tree *nelts) parser->type_definition_forbidden_message = "types may not be defined in a new-type-id"; /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + /*is_trailing_return=*/false, &type_specifier_seq); /* Restore the old message. */ parser->type_definition_forbidden_message = saved_message; @@ -6955,8 +6967,8 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword) /* Lambdas that appear in variable initializer or default argument scope get that in their mangling, so we need to record it. We might as well use the count for function and namespace scopes as well. */ -static tree lambda_scope; -static int lambda_count; +static GTY(()) tree lambda_scope; +static GTY(()) int lambda_count; typedef struct GTY(()) tree_int { tree t; @@ -7080,6 +7092,8 @@ cp_parser_lambda_expression (cp_parser* parser) LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) = newlist; } + maybe_add_lambda_conv_op (type); + type = finish_struct (type, /*attributes=*/NULL_TREE); parser->num_template_parameter_lists = saved_num_template_parameter_lists; @@ -7125,6 +7139,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) tree capture_id; tree capture_init_expr; cp_id_kind idk = CP_ID_KIND_NONE; + bool explicit_init_p = false; enum capture_kind_type { @@ -7151,7 +7166,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) add_capture (lambda_expr, /*id=*/get_identifier ("__this"), /*initializer=*/finish_this_expr(), - /*by_reference_p=*/false); + /*by_reference_p=*/false, + explicit_init_p); continue; } @@ -7176,7 +7192,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) /*recovering=*/true, /*or_comma=*/true, /*consume_paren=*/true); - continue; + break; } /* Find the initializer for this capture. */ @@ -7190,6 +7206,7 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) capture_init_expr = cp_parser_assignment_expression (parser, /*cast_p=*/true, &idk); + explicit_init_p = true; } else { @@ -7231,7 +7248,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr) add_capture (lambda_expr, capture_id, capture_init_expr, - /*by_reference_p=*/capture_kind == BY_REFERENCE); + /*by_reference_p=*/capture_kind == BY_REFERENCE, + explicit_init_p); } cp_parser_require (parser, CPP_CLOSE_SQUARE, "%<]%>"); @@ -7333,15 +7351,25 @@ cp_parser_lambda_declarator_opt (cp_parser* parser, tree lambda_expr) declarator = make_id_declarator (NULL_TREE, ansi_opname (CALL_EXPR), sfk_none); - quals = (LAMBDA_EXPR_MUTABLE_P (lambda_expr) - ? TYPE_UNQUALIFIED : TYPE_QUAL_CONST); + quals = TYPE_UNQUALIFIED; + if (LAMBDA_EXPR_CAPTURE_LIST (lambda_expr) == NULL_TREE + && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) == CPLD_NONE) + { + /* A lambda with no captures has a static op() and a conversion op + to function type. */ + if (LAMBDA_EXPR_MUTABLE_P (lambda_expr)) + error ("lambda expression with no captures declared mutable"); + return_type_specs.storage_class = sc_static; + } + else if (!LAMBDA_EXPR_MUTABLE_P (lambda_expr)) + quals = TYPE_QUAL_CONST; declarator = make_call_declarator (declarator, param_list, quals, exception_spec, /*late_return_type=*/NULL_TREE); fco = grokmethod (&return_type_specs, - declarator, - attributes); + declarator, + attributes); DECL_INITIALIZED_IN_CLASS_P (fco) = 1; DECL_ARTIFICIAL (fco) = 1; @@ -7734,12 +7762,21 @@ static tree cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr) { tree statement = NULL_TREE; + cp_token *token = cp_lexer_peek_token (parser->lexer); /* If the next token is a ';', then there is no expression statement. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)) statement = cp_parser_expression (parser, /*cast_p=*/false, NULL); + /* Give a helpful message for "A::type t;" */ + if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON) + && !cp_parser_uncommitted_to_tentative_parse_p (parser) + && TREE_CODE (statement) == SCOPE_REF) + error_at (token->location, "need % before %qE to name " + "a type in dependent scope %qT", + statement, TREE_OPERAND (statement, 0)); + /* Consume the final `;'. */ cp_parser_consume_semicolon_at_end_of_statement (parser); @@ -8023,7 +8060,8 @@ cp_parser_condition (cp_parser* parser) parser->type_definition_forbidden_message = "types may not be defined in conditions"; /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_condition==*/true, + cp_parser_type_specifier_seq (parser, /*is_declaration==*/true, + /*is_trailing_return=*/false, &type_specifiers); /* Restore the saved message. */ parser->type_definition_forbidden_message = saved_message; @@ -9537,12 +9575,25 @@ cp_parser_decltype (cp_parser *parser) cp_parser_parse_definitely (parser); else { + bool saved_greater_than_is_operator_p; + /* Abort our attempt to parse an id-expression or member access expression. */ cp_parser_abort_tentative_parse (parser); + /* Within a parenthesized expression, a `>' token is always + the greater-than operator. */ + saved_greater_than_is_operator_p + = parser->greater_than_is_operator_p; + parser->greater_than_is_operator_p = true; + /* Parse a full expression. */ expr = cp_parser_expression (parser, /*cast_p=*/false, NULL); + + /* The `>' token might be the end of a template-id or + template-parameter-list now. */ + parser->greater_than_is_operator_p + = saved_greater_than_is_operator_p; } /* Go back to evaluating expressions. */ @@ -9651,7 +9702,8 @@ cp_parser_conversion_type_id (cp_parser* parser) /* Parse the attributes. */ attributes = cp_parser_attributes_opt (parser); /* Parse the type-specifiers. */ - cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + /*is_trailing_return=*/false, &type_specifiers); /* If that didn't work, stop. */ if (type_specifiers.type == error_mark_node) @@ -11627,6 +11679,9 @@ cp_parser_type_specifier (cp_parser* parser, switch (keyword) { case RID_ENUM: + if ((flags & CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS)) + goto elaborated_type_specifier; + /* Look for the enum-specifier. */ type_spec = cp_parser_enum_specifier (parser); /* If that worked, we're done. */ @@ -11649,6 +11704,9 @@ cp_parser_type_specifier (cp_parser* parser, case RID_CLASS: case RID_STRUCT: case RID_UNION: + if ((flags & CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS)) + goto elaborated_type_specifier; + /* Parse tentatively so that we can back up if we don't find a class-specifier. */ cp_parser_parse_tentatively (parser); @@ -12514,7 +12572,8 @@ cp_parser_enum_specifier (cp_parser* parser) cp_lexer_consume_token (parser->lexer); /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + /*is_trailing_return=*/false, &type_specifiers); /* At this point this is surely not elaborated type specifier. */ @@ -12798,7 +12857,7 @@ cp_parser_namespace_definition (cp_parser* parser) #ifdef HANDLE_PRAGMA_VISIBILITY if (has_visibility) - pop_visibility (); + pop_visibility (1); #endif /* Finish the namespace. */ @@ -14405,7 +14464,7 @@ cp_parser_cv_qualifier_seq_opt (cp_parser* parser) /* Parse a late-specified return type, if any. This is not a separate non-terminal, but part of a function declarator, which looks like - -> type-id + -> trailing-type-specifier-seq abstract-declarator(opt) Returns the type indicated by the type-id. */ @@ -14423,7 +14482,7 @@ cp_parser_late_return_type_opt (cp_parser* parser) /* Consume the ->. */ cp_lexer_consume_token (parser->lexer); - return cp_parser_type_id (parser); + return cp_parser_trailing_type_id (parser); } /* Parse a declarator-id. @@ -14476,13 +14535,15 @@ cp_parser_declarator_id (cp_parser* parser, bool optional_p) Returns the TYPE specified. */ static tree -cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg) +cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg, + bool is_trailing_return) { cp_decl_specifier_seq type_specifier_seq; cp_declarator *abstract_declarator; /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + cp_parser_type_specifier_seq (parser, /*is_declaration=*/false, + is_trailing_return, &type_specifier_seq); if (type_specifier_seq.type == error_mark_node) return error_mark_node; @@ -14520,12 +14581,17 @@ cp_parser_type_id_1 (cp_parser* parser, bool is_template_arg) static tree cp_parser_type_id (cp_parser *parser) { - return cp_parser_type_id_1 (parser, false); + return cp_parser_type_id_1 (parser, false, false); } static tree cp_parser_template_type_arg (cp_parser *parser) { - return cp_parser_type_id_1 (parser, true); + return cp_parser_type_id_1 (parser, true, false); +} + +static tree cp_parser_trailing_type_id (cp_parser *parser) +{ + return cp_parser_type_id_1 (parser, false, true); } /* Parse a type-specifier-seq. @@ -14538,14 +14604,18 @@ static tree cp_parser_template_type_arg (cp_parser *parser) type-specifier-seq: attributes type-specifier-seq [opt] - If IS_CONDITION is true, we are at the start of a "condition", - e.g., we've just seen "if (". + If IS_DECLARATION is true, we are at the start of a "condition" or + exception-declaration, so we might be followed by a declarator-id. + + If IS_TRAILING_RETURN is true, we are in a trailing-return-type, + i.e. we've just seen "->". Sets *TYPE_SPECIFIER_SEQ to represent the sequence. */ static void cp_parser_type_specifier_seq (cp_parser* parser, - bool is_condition, + bool is_declaration, + bool is_trailing_return, cp_decl_specifier_seq *type_specifier_seq) { bool seen_type_specifier = false; @@ -14555,6 +14625,12 @@ cp_parser_type_specifier_seq (cp_parser* parser, /* Clear the TYPE_SPECIFIER_SEQ. */ clear_decl_specs (type_specifier_seq); + /* In the context of a trailing return type, enum E { } is an + elaborated-type-specifier followed by a function-body, not an + enum-specifier. */ + if (is_trailing_return) + flags |= CP_PARSER_FLAGS_NO_TYPE_DEFINITIONS; + /* Parse the type-specifiers and attributes. */ while (true) { @@ -14614,7 +14690,7 @@ cp_parser_type_specifier_seq (cp_parser* parser, would be clearer just to allow a decl-specifier-seq here, and then add a semantic restriction that if any decl-specifiers that are not type-specifiers appear, the program is invalid. */ - if (is_condition && !is_cv_qualifier) + if (is_declaration && !is_cv_qualifier) flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES; } @@ -17265,7 +17341,8 @@ cp_parser_exception_declaration (cp_parser* parser) = "types may not be defined in exception-declarations"; /* Parse the type-specifier-seq. */ - cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + cp_parser_type_specifier_seq (parser, /*is_declaration=*/true, + /*is_trailing_return=*/false, &type_specifiers); /* If it's a `)', then there is no declarator. */ if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)) @@ -18131,11 +18208,15 @@ cp_parser_check_template_parameters (cp_parser* parser, template void S::R::f (); */ if (parser->num_template_parameter_lists < num_templates) { - if (declarator) + if (declarator && !current_function_decl) error_at (location, "specializing member %<%T::%E%> " "requires %%> syntax", declarator->u.id.qualifying_scope, declarator->u.id.unqualified_name); + else if (declarator) + error_at (location, "invalid declaration of %<%T::%E%>", + declarator->u.id.qualifying_scope, + declarator->u.id.unqualified_name); else error_at (location, "too few template-parameter-lists"); return false; @@ -22038,7 +22119,8 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) cp_parser_condition, from whence the bulk of this is copied. */ cp_parser_parse_tentatively (parser); - cp_parser_type_specifier_seq (parser, /*is_condition=*/false, + cp_parser_type_specifier_seq (parser, /*is_declaration=*/true, + /*is_trailing_return=*/false, &type_specifiers); if (cp_parser_parse_definitely (parser)) { @@ -22357,7 +22439,8 @@ cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses) } collapse_err = true; cp_parser_statement_seq_opt (parser, NULL); - cp_parser_require (parser, CPP_CLOSE_BRACE, "%<}%>"); + if (cp_lexer_next_token_is (parser->lexer, CPP_EOF)) + break; } } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6b98956d6e6..dd453c526cc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -1501,7 +1501,8 @@ iterative_hash_template_arg (tree arg, hashval_t val) } case PARM_DECL: - val = iterative_hash_object (DECL_PARM_INDEX (arg), val); + if (!DECL_ARTIFICIAL (arg)) + val = iterative_hash_object (DECL_PARM_INDEX (arg), val); return iterative_hash_template_arg (TREE_TYPE (arg), val); case TARGET_EXPR: @@ -1640,13 +1641,20 @@ void print_candidates (tree fns) { tree fn; + tree f; const char *str = "candidates are:"; - for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn)) + if (is_overloaded_fn (fns)) + { + for (f = fns; f; f = OVL_NEXT (f)) + { + error ("%s %+#D", str, OVL_CURRENT (f)); + str = " "; + } + } + else for (fn = fns; fn != NULL_TREE; fn = TREE_CHAIN (fn)) { - tree f; - for (f = TREE_VALUE (fn); f; f = OVL_NEXT (f)) error ("%s %+#D", str, OVL_CURRENT (f)); str = " "; @@ -4025,7 +4033,8 @@ check_default_tmpl_args (tree decl, tree parms, int is_primary, else if (is_friend_decl) msg = "default template arguments may not be used in function template friend declarations"; else if (TREE_CODE (decl) == FUNCTION_DECL && (cxx_dialect == cxx98)) - msg = "default template arguments may not be used in function templates"; + msg = ("default template arguments may not be used in function templates " + "without -std=c++0x or -std=gnu++0x"); else if (is_partial) msg = "default template arguments may not be used in partial specializations"; else @@ -4677,6 +4686,22 @@ convert_nontype_argument_function (tree type, tree expr) return fn; } +/* Subroutine of convert_nontype_argument. + Check if EXPR of type TYPE is a valid pointer-to-member constant. + Emit an error otherwise. */ + +static bool +check_valid_ptrmem_cst_expr (tree type, tree expr) +{ + STRIP_NOPS (expr); + if (expr && (null_ptr_cst_p (expr) || TREE_CODE (expr) == PTRMEM_CST)) + return true; + error ("%qE is not a valid template argument for type %qT", + expr, type); + error ("it must be a pointer-to-member of the form `&X::Y'"); + return false; +} + /* Attempt to convert the non-type template parameter EXPR to the indicated TYPE. If the conversion is successful, return the converted value. If the conversion is unsuccessful, return @@ -4976,6 +5001,11 @@ convert_nontype_argument (tree type, tree expr) if (expr == error_mark_node) return error_mark_node; + /* [temp.arg.nontype] bullet 1 says the pointer to member + expression must be a pointer-to-member constant. */ + if (!check_valid_ptrmem_cst_expr (type, expr)) + return error_mark_node; + /* There is no way to disable standard conversions in resolve_address_of_overloaded_function (called by instantiate_type). It is possible that the call succeeded by @@ -5002,6 +5032,11 @@ convert_nontype_argument (tree type, tree expr) qualification conversions (_conv.qual_) are applied. */ else if (TYPE_PTRMEM_P (type)) { + /* [temp.arg.nontype] bullet 1 says the pointer to member + expression must be a pointer-to-member constant. */ + if (!check_valid_ptrmem_cst_expr (type, expr)) + return error_mark_node; + expr = perform_qualification_conversions (type, expr); if (expr == error_mark_node) return expr; @@ -5817,6 +5852,18 @@ template_args_equal (tree ot, tree nt) return 0; return 1; } + else if (ot && TREE_CODE (ot) == ARGUMENT_PACK_SELECT) + { + /* We get here probably because we are in the middle of substituting + into the pattern of a pack expansion. In that case the + ARGUMENT_PACK_SELECT temporarily replaces the pack argument we are + interested in. So we want to use the initial pack argument for + the comparison. */ + ot = ARGUMENT_PACK_SELECT_FROM_PACK (ot); + if (nt && TREE_CODE (nt) == ARGUMENT_PACK_SELECT) + nt = ARGUMENT_PACK_SELECT_FROM_PACK (nt); + return template_args_equal (ot, nt); + } else if (TYPE_P (nt)) return TYPE_P (ot) && same_type_p (ot, nt); else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot)) @@ -7305,13 +7352,14 @@ instantiate_class_template (tree type) tree typedecl; tree pbinfo; tree base_list; + unsigned int saved_maximum_field_alignment; if (type == error_mark_node) return error_mark_node; if (TYPE_BEING_DEFINED (type) || COMPLETE_TYPE_P (type) - || dependent_type_p (type)) + || uses_template_parms (type)) return type; /* Figure out which template is being instantiated. */ @@ -7365,6 +7413,9 @@ instantiate_class_template (tree type) push_deferring_access_checks (dk_no_deferred); push_to_top_level (); + /* Use #pragma pack from the template context. */ + saved_maximum_field_alignment = maximum_field_alignment; + maximum_field_alignment = TYPE_PRECISION (pattern); SET_CLASSTYPE_INTERFACE_UNKNOWN (type); @@ -7780,6 +7831,7 @@ instantiate_class_template (tree type) perform_typedefs_access_check (pattern, args); perform_deferred_access_checks (); pop_nested_class (); + maximum_field_alignment = saved_maximum_field_alignment; pop_from_top_level (); pop_deferring_access_checks (); pop_tinst_level (); @@ -7944,6 +7996,10 @@ tsubst_pack_expansion (tree t, tree args, tsubst_flags_t complain, } else if (len != my_len) { + if (incomplete) + /* We got explicit args for some packs but not others; + do nothing now and try again after deduction. */ + return t; if (TREE_CODE (t) == TYPE_PACK_EXPANSION) error ("mismatched argument pack lengths while expanding " "%<%T%>", @@ -8457,6 +8513,7 @@ tsubst_default_arguments (tree fn) static tree tsubst_decl (tree t, tree args, tsubst_flags_t complain) { +#define RETURN(EXP) do { r = (EXP); goto out; } while(0) location_t saved_loc; tree r = NULL_TREE; tree in_decl = t; @@ -8482,7 +8539,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* Template template parameter is treated here. */ tree new_type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (new_type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); r = copy_decl (t); TREE_CHAIN (r) = NULL_TREE; @@ -8513,12 +8570,12 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) complain, in_decl); --processing_template_decl; if (full_args == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); /* If this is a default template template argument, tsubst might not have changed anything. */ if (full_args == tmpl_args) - return t; + RETURN (t); hash = hash_tmpl_and_args (t, full_args); spec = retrieve_specialization (t, full_args, hash); @@ -8546,7 +8603,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) new_type = tsubst (TREE_TYPE (t), args, complain, in_decl); --processing_template_decl; if (new_type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); TREE_TYPE (r) = new_type; CLASSTYPE_TI_TEMPLATE (new_type) = r; @@ -8561,7 +8618,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) new_decl = tsubst (decl, args, complain, in_decl); --processing_template_decl; if (new_decl == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); DECL_TEMPLATE_RESULT (r) = new_decl; DECL_TI_TEMPLATE (new_decl) = r; @@ -8619,7 +8676,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) dependent_p = value_dependent_expression_p (t); --processing_template_decl; if (!dependent_p) - return t; + RETURN (t); /* Calculate the most general template of which R is a specialization, and the complete set of arguments used to @@ -8710,7 +8767,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) } type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); /* We do NOT check for matching decls pushed separately at this point, as they may not represent instantiations of this @@ -8753,6 +8810,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* We'll re-clone as appropriate in instantiate_template. */ DECL_CLONED_FUNCTION (r) = NULL_TREE; + /* If we aren't complaining now, return on error before we register + the specialization so that we'll complain eventually. */ + if ((complain & tf_error) == 0 + && IDENTIFIER_OPNAME_P (DECL_NAME (r)) + && !grok_op_properties (r, /*complain=*/false)) + RETURN (error_mark_node); + /* Set up the DECL_TEMPLATE_INFO for R. There's no need to do this in the special friend case mentioned above where GEN_TMPL is NULL. */ @@ -8804,9 +8868,10 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (PRIMARY_TEMPLATE_P (gen_tmpl)) clone_function_decl (r, /*update_method_vec_p=*/0); } - else if (IDENTIFIER_OPNAME_P (DECL_NAME (r)) - && !grok_op_properties (r, (complain & tf_error) != 0)) - return error_mark_node; + else if ((complain & tf_error) != 0 + && IDENTIFIER_OPNAME_P (DECL_NAME (r)) + && !grok_op_properties (r, /*complain=*/true)) + RETURN (error_mark_node); if (DECL_FRIEND_P (t) && DECL_FRIEND_CONTEXT (t)) SET_DECL_FRIEND_CONTEXT (r, @@ -8822,6 +8887,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) = remove_attribute ("visibility", DECL_ATTRIBUTES (r)); } determine_visibility (r); + if (DECL_DEFAULTED_OUTSIDE_CLASS_P (r) + && !processing_template_decl) + defaulted_late_check (r); apply_late_template_attributes (&r, DECL_ATTRIBUTES (r), 0, args, complain, in_decl); @@ -8847,7 +8915,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) if (spec && TREE_CODE (spec) == PARM_DECL && TREE_CODE (TREE_TYPE (spec)) != TYPE_PACK_EXPANSION) - return spec; + RETURN (spec); /* Expand the TYPE_PACK_EXPANSION that provides the types for the parameters in this function parameter pack. */ @@ -8860,8 +8928,8 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* Zero-length parameter packs are boring. Just substitute into the chain. */ if (len == 0) - return tsubst (TREE_CHAIN (t), args, complain, - TREE_CHAIN (t)); + RETURN (tsubst (TREE_CHAIN (t), args, complain, + TREE_CHAIN (t))); } else { @@ -8951,7 +9019,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) r = copy_decl (t); type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); TREE_TYPE (r) = type; cp_apply_type_quals_to_decl (cp_type_quals (type), r); @@ -9014,7 +9082,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) we've copied the type for a typedef. */ type = tsubst (TREE_TYPE (t), args, complain, in_decl); if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); r = TYPE_NAME (type); break; } @@ -9087,7 +9155,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) DECL_INITIALIZED_P (r) = 0; DECL_TEMPLATE_INSTANTIATED (r) = 0; if (type == error_mark_node) - return error_mark_node; + RETURN (error_mark_node); if (TREE_CODE (type) == FUNCTION_TYPE) { /* It may seem that this case cannot occur, since: @@ -9107,7 +9175,7 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) /* R is not yet sufficiently initialized, so we just use its name. */ DECL_NAME (r)); - return error_mark_node; + RETURN (error_mark_node); } type = complete_type (type); DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (r) @@ -9203,7 +9271,9 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain) default: gcc_unreachable (); } +#undef RETURN + out: /* Restore the file and line information. */ input_location = saved_loc; @@ -9945,13 +10015,8 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) { /* The type of the implicit object parameter gets its cv-qualifiers from the FUNCTION_TYPE. */ - tree method_type; - tree this_type = cp_build_qualified_type (TYPE_MAIN_VARIANT (r), - cp_type_quals (type)); tree memptr; - method_type = build_method_type_directly (this_type, - TREE_TYPE (type), - TYPE_ARG_TYPES (type)); + tree method_type = build_memfn_type (type, r, cp_type_quals (type)); memptr = build_ptrmemfunc_type (build_pointer_type (method_type)); return cp_build_qualified_type_real (memptr, cp_type_quals (t), complain); @@ -12440,7 +12505,7 @@ tsubst_copy_and_build (tree t, } /* Verify that the instantiated ARGS are valid. For type arguments, - make sure that the type is not variably modified. For non-type arguments, + make sure that the type's linkage is ok. For non-type arguments, make sure they are constants if they are integral or enumerations. Emit an error under control of COMPLAIN, and return TRUE on error. */ @@ -12461,7 +12526,33 @@ check_instantiated_arg (tree tmpl, tree t, tsubst_flags_t complain) } else if (TYPE_P (t)) { - if (variably_modified_type_p (t, NULL_TREE)) + /* [basic.link]: A name with no linkage (notably, the name + of a class or enumeration declared in a local scope) + shall not be used to declare an entity with linkage. + This implies that names with no linkage cannot be used as + template arguments + + DR 757 relaxes this restriction for C++0x. */ + tree nt = (cxx_dialect > cxx98 ? NULL_TREE + : no_linkage_check (t, /*relaxed_p=*/false)); + + if (nt) + { + /* DR 488 makes use of a type with no linkage cause + type deduction to fail. */ + if (complain & tf_error) + { + if (TYPE_ANONYMOUS_P (nt)) + error ("%qT is/uses anonymous type", t); + else + error ("template argument for %qD uses local type %qT", + tmpl, t); + } + return true; + } + /* In order to avoid all sorts of complications, we do not + allow variably-modified types as template arguments. */ + else if (variably_modified_type_p (t, NULL_TREE)) { if (complain & tf_error) error ("%qT is a variably modified type", t); @@ -12891,7 +12982,17 @@ maybe_adjust_types_for_deduction (unification_kind_t strict, } case DEDUCE_EXACT: - /* There is nothing to do in this case. */ + /* Core issue #873: Do the DR606 thing (see below) for these cases, + too, but here handle it by stripping the reference from PARM + rather than by adding it to ARG. */ + if (TREE_CODE (*parm) == REFERENCE_TYPE + && TYPE_REF_IS_RVALUE (*parm) + && TREE_CODE (TREE_TYPE (*parm)) == TEMPLATE_TYPE_PARM + && cp_type_quals (TREE_TYPE (*parm)) == TYPE_UNQUALIFIED + && TREE_CODE (*arg) == REFERENCE_TYPE + && !TYPE_REF_IS_RVALUE (*arg)) + *parm = TREE_TYPE (*parm); + /* Nothing else to do in this case. */ return 0; default: @@ -13153,9 +13254,11 @@ type_unification_real (tree tparms, to explicitly check cxx_dialect here. */ if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i))) { - tree arg = tsubst_template_arg - (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)), - targs, tf_none, NULL_TREE); + tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i)); + tree arg = TREE_PURPOSE (TREE_VEC_ELT (tparms, i)); + arg = tsubst_template_arg (arg, targs, tf_none, NULL_TREE); + arg = convert_template_argument (parm, arg, targs, tf_none, + i, NULL_TREE); if (arg == error_mark_node) return 1; else @@ -13303,6 +13406,105 @@ resolve_overloaded_unification (tree tparms, return false; } +/* Core DR 115: In contexts where deduction is done and fails, or in + contexts where deduction is not done, if a template argument list is + specified and it, along with any default template arguments, identifies + a single function template specialization, then the template-id is an + lvalue for the function template specialization. */ + +tree +resolve_nondeduced_context (tree orig_expr) +{ + tree expr, offset, baselink; + bool addr; + + if (!type_unknown_p (orig_expr)) + return orig_expr; + + expr = orig_expr; + addr = false; + offset = NULL_TREE; + baselink = NULL_TREE; + + if (TREE_CODE (expr) == ADDR_EXPR) + { + expr = TREE_OPERAND (expr, 0); + addr = true; + } + if (TREE_CODE (expr) == OFFSET_REF) + { + offset = expr; + expr = TREE_OPERAND (expr, 1); + } + if (TREE_CODE (expr) == BASELINK) + { + baselink = expr; + expr = BASELINK_FUNCTIONS (expr); + } + + if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) + { + int good = 0; + tree goodfn = NULL_TREE; + + /* If we got some explicit template args, we need to plug them into + the affected templates before we try to unify, in case the + explicit args will completely resolve the templates in question. */ + + tree expl_subargs = TREE_OPERAND (expr, 1); + tree arg = TREE_OPERAND (expr, 0); + tree badfn = NULL_TREE; + tree badargs = NULL_TREE; + + for (; arg; arg = OVL_NEXT (arg)) + { + tree fn = OVL_CURRENT (arg); + tree subargs, elem; + + if (TREE_CODE (fn) != TEMPLATE_DECL) + continue; + + ++processing_template_decl; + subargs = get_bindings (fn, DECL_TEMPLATE_RESULT (fn), + expl_subargs, /*check_ret=*/false); + if (subargs && !any_dependent_template_arguments_p (subargs)) + { + elem = instantiate_template (fn, subargs, tf_none); + if (elem == error_mark_node) + { + badfn = fn; + badargs = subargs; + } + else if (elem && (!goodfn || !decls_match (goodfn, elem))) + { + goodfn = elem; + ++good; + } + } + --processing_template_decl; + } + if (good == 1) + { + expr = goodfn; + if (baselink) + expr = build_baselink (BASELINK_BINFO (baselink), + BASELINK_ACCESS_BINFO (baselink), + expr, BASELINK_OPTYPE (baselink)); + if (offset) + expr = build2 (OFFSET_REF, TREE_TYPE (expr), + TREE_OPERAND (offset, 0), expr); + if (addr) + expr = build_address (expr); + return expr; + } + else if (good == 0 && badargs) + /* There were no good options and at least one bad one, so let the + user know what the problem is. */ + instantiate_template (badfn, badargs, tf_warning_or_error); + } + return orig_expr; +} + /* Subroutine of resolve_overloaded_unification; does deduction for a single overload. Fills TARGS with any deduced arguments, or error_mark_node if different overloads deduce different arguments for a given parm. @@ -14652,6 +14854,35 @@ mark_decl_instantiated (tree result, int extern_p) DECL_INTERFACE_KNOWN (result) = 1; } +/* Subroutine of more_specialized_fn: check whether TARGS is missing any + important template arguments. If any are missing, we check whether + they're important by using error_mark_node for substituting into any + args that were used for partial ordering (the ones between ARGS and END) + and seeing if it bubbles up. */ + +static bool +check_undeduced_parms (tree targs, tree args, tree end) +{ + bool found = false; + int i; + for (i = TREE_VEC_LENGTH (targs) - 1; i >= 0; --i) + if (TREE_VEC_ELT (targs, i) == NULL_TREE) + { + found = true; + TREE_VEC_ELT (targs, i) = error_mark_node; + } + if (found) + { + for (; args != end; args = TREE_CHAIN (args)) + { + tree substed = tsubst (TREE_VALUE (args), targs, tf_none, NULL_TREE); + if (substed == error_mark_node) + return true; + } + } + return false; +} + /* Given two function templates PAT1 and PAT2, return: 1 if PAT1 is more specialized than PAT2 as described in [temp.func.order]. @@ -14675,8 +14906,12 @@ mark_decl_instantiated (tree result, int extern_p) neither is more cv-qualified, they both are equal). Unlike regular deduction, after all the arguments have been deduced in this way, we do *not* verify the deduced template argument values can be - substituted into non-deduced contexts, nor do we have to verify - that all template arguments have been deduced. */ + substituted into non-deduced contexts. + + The logic can be a bit confusing here, because we look at deduce1 and + targs1 to see if pat2 is at least as specialized, and vice versa; if we + can find template arguments for pat1 to make arg1 look like arg2, that + means that arg2 is at least as specialized as arg1. */ int more_specialized_fn (tree pat1, tree pat2, int len) @@ -14689,8 +14924,9 @@ more_specialized_fn (tree pat1, tree pat2, int len) tree tparms2 = DECL_INNERMOST_TEMPLATE_PARMS (pat2); tree args1 = TYPE_ARG_TYPES (TREE_TYPE (decl1)); tree args2 = TYPE_ARG_TYPES (TREE_TYPE (decl2)); - int better1 = 0; - int better2 = 0; + tree origs1, origs2; + bool lose1 = false; + bool lose2 = false; /* Remove the this parameter from non-static member functions. If one is a non-static member function and the other is not a static @@ -14729,6 +14965,9 @@ more_specialized_fn (tree pat1, tree pat2, int len) processing_template_decl++; + origs1 = args1; + origs2 = args2; + while (len-- /* Stop when an ellipsis is seen. */ && args1 != NULL_TREE && args2 != NULL_TREE) @@ -14863,28 +15102,37 @@ more_specialized_fn (tree pat1, tree pat2, int len) deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE); } + /* If we couldn't deduce arguments for tparms1 to make arg1 match + arg2, then arg2 is not as specialized as arg1. */ if (!deduce1) - better2 = -1; + lose2 = true; if (!deduce2) - better1 = -1; - if (better1 < 0 && better2 < 0) - /* We've failed to deduce something in either direction. - These must be unordered. */ - break; - - if (deduce1 && deduce2 && quals1 >= 0 && quals2 >= 0) + lose1 = true; + + /* "If, for a given type, deduction succeeds in both directions + (i.e., the types are identical after the transformations above) + and if the type from the argument template is more cv-qualified + than the type from the parameter template (as described above) + that type is considered to be more specialized than the other. If + neither type is more cv-qualified than the other then neither type + is more specialized than the other." + + We check same_type_p explicitly because deduction can also succeed + in both directions when there is a nondeduced context. */ + if (deduce1 && deduce2 + && quals1 != quals2 && quals1 >= 0 && quals2 >= 0 + && same_type_p (arg1, arg2)) { - /* Deduces in both directions, see if quals can - disambiguate. Pretend the worse one failed to deduce. */ if ((quals1 & quals2) == quals2) - deduce1 = 0; + lose2 = true; if ((quals1 & quals2) == quals1) - deduce2 = 0; + lose1 = true; } - if (deduce1 && !deduce2 && !better2) - better2 = 1; - if (deduce2 && !deduce1 && !better1) - better1 = 1; + + if (lose1 && lose2) + /* We've failed to deduce something in either direction. + These must be unordered. */ + break; if (TREE_CODE (arg1) == TYPE_PACK_EXPANSION || TREE_CODE (arg2) == TYPE_PACK_EXPANSION) @@ -14896,22 +15144,38 @@ more_specialized_fn (tree pat1, tree pat2, int len) args2 = TREE_CHAIN (args2); } + /* "In most cases, all template parameters must have values in order for + deduction to succeed, but for partial ordering purposes a template + parameter may remain without a value provided it is not used in the + types being used for partial ordering." + + Thus, if we are missing any of the targs1 we need to substitute into + origs1, then pat2 is not as specialized as pat1. This can happen when + there is a nondeduced context. */ + if (!lose2 && check_undeduced_parms (targs1, origs1, args1)) + lose2 = true; + if (!lose1 && check_undeduced_parms (targs2, origs2, args2)) + lose1 = true; + processing_template_decl--; /* All things being equal, if the next argument is a pack expansion for one function but not for the other, prefer the - non-variadic function. */ - if ((better1 > 0) - (better2 > 0) == 0 + non-variadic function. FIXME this is bogus; see c++/41958. */ + if (lose1 == lose2 && args1 && TREE_VALUE (args1) && args2 && TREE_VALUE (args2)) { - if (TREE_CODE (TREE_VALUE (args1)) == TYPE_PACK_EXPANSION) - return TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION ? 0 : -1; - else if (TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION) - return 1; + lose1 = TREE_CODE (TREE_VALUE (args1)) == TYPE_PACK_EXPANSION; + lose2 = TREE_CODE (TREE_VALUE (args2)) == TYPE_PACK_EXPANSION; } - return (better1 > 0) - (better2 > 0); + if (lose1 == lose2) + return 0; + else if (!lose1) + return 1; + else + return -1; } /* Determine which of two partial specializations is more specialized. @@ -17594,10 +17858,7 @@ make_args_non_dependent (VEC(tree,gc) *args) tree make_auto (void) { - tree au; - - /* ??? Is it worth caching this for multiple autos at the same level? */ - au = cxx_make_type (TEMPLATE_TYPE_PARM); + tree au = cxx_make_type (TEMPLATE_TYPE_PARM); TYPE_NAME (au) = build_decl (BUILTINS_LOCATION, TYPE_DECL, get_identifier ("auto"), au); TYPE_STUB_DECL (au) = TYPE_NAME (au); @@ -17675,6 +17936,19 @@ do_auto_deduction (tree type, tree init, tree auto_node) return error_mark_node; } + /* If the list of declarators contains more than one declarator, the type + of each declared variable is determined as described above. If the + type deduced for the template parameter U is not the same in each + deduction, the program is ill-formed. */ + if (TREE_TYPE (auto_node) + && !same_type_p (TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0))) + { + error ("inconsistent deduction for %qT: %qT and then %qT", + auto_node, TREE_TYPE (auto_node), TREE_VEC_ELT (targs, 0)); + return error_mark_node; + } + TREE_TYPE (auto_node) = TREE_VEC_ELT (targs, 0); + if (processing_template_decl) targs = add_to_template_args (current_template_args (), targs); return tsubst (type, targs, tf_warning_or_error, NULL_TREE); diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 8dde479a6c4..3fb6d11c0ce 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -102,7 +102,7 @@ VEC(tree,gc) *unemitted_tinfo_decls; static GTY (()) VEC(tinfo_s,gc) *tinfo_descs; static tree ifnonnull (tree, tree); -static tree tinfo_name (tree); +static tree tinfo_name (tree, bool); static tree build_dynamic_cast_1 (tree, tree, tsubst_flags_t); static tree throw_bad_cast (void); static tree throw_bad_typeid (void); @@ -128,13 +128,13 @@ static void push_abi_namespace (void) { push_nested_namespace (abi_node); - push_visibility ("default"); + push_visibility ("default", 2); } static void pop_abi_namespace (void) { - pop_visibility (); + pop_visibility (2); pop_nested_namespace (abi_node); } @@ -349,16 +349,30 @@ build_typeid (tree exp) return exp; } -/* Generate the NTBS name of a type. */ +/* Generate the NTBS name of a type. If MARK_PRIVATE, put a '*' in front so that + comparisons will be done by pointer rather than string comparison. */ static tree -tinfo_name (tree type) +tinfo_name (tree type, bool mark_private) { const char *name; + int length; tree name_string; - name = mangle_type_string_for_rtti (type); - name_string = fix_string_type (build_string (strlen (name) + 1, name)); - return name_string; + name = mangle_type_string (type); + length = strlen (name); + + if (mark_private) + { + /* Inject '*' at beginning of name to force pointer comparison. */ + char* buf = (char*) XALLOCAVEC (char, length + 2); + buf[0] = '*'; + memcpy (buf + 1, name, length + 1); + name_string = build_string (length + 2, buf); + } + else + name_string = build_string (length + 1, name); + + return fix_string_type (name_string); } /* Return a VAR_DECL for the internal ABI defined type_info object for @@ -839,13 +853,12 @@ tinfo_base_init (tinfo_s *ti, tree target) tree vtable_ptr; { - tree name_name; + tree name_name, name_string; /* Generate the NTBS array variable. */ tree name_type = build_cplus_array_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST), NULL_TREE); - tree name_string = tinfo_name (target); /* Determine the name of the variable -- and remember with which type it is associated. */ @@ -862,6 +875,7 @@ tinfo_base_init (tinfo_s *ti, tree target) DECL_TINFO_P (name_decl) = 1; set_linkage_according_to_type (target, name_decl); import_export_decl (name_decl); + name_string = tinfo_name (target, !TREE_PUBLIC (name_decl)); DECL_INITIAL (name_decl) = name_string; mark_used (name_decl); pushdecl_top_level_and_finish (name_decl, name_string); diff --git a/gcc/cp/search.c b/gcc/cp/search.c index d6521fb6f82..3adf9e0a1ab 100644 --- a/gcc/cp/search.c +++ b/gcc/cp/search.c @@ -214,9 +214,12 @@ lookup_base (tree t, tree base, base_access access, base_kind *kind_ptr) t_binfo = TYPE_BINFO (t); } - base = complete_type (TYPE_MAIN_VARIANT (base)); + base = TYPE_MAIN_VARIANT (base); - if (t_binfo) + /* If BASE is incomplete, it can't be a base of T--and instantiating it + might cause an error. */ + if (t_binfo && CLASS_TYPE_P (base) + && (COMPLETE_TYPE_P (base) || TYPE_BEING_DEFINED (base))) { struct lookup_base_data_s data; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 8199af0e693..e270a734fa0 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -56,6 +56,7 @@ along with GCC; see the file COPYING3. If not see static tree maybe_convert_cond (tree); static tree finalize_nrv_r (tree *, int *, void *); static tree capture_decltype (tree); +static tree thisify_lambda_field (tree); /* Deferred Access Checking Overview @@ -1447,14 +1448,13 @@ finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) return error_mark_node; } - /* If decl is a field, object has a lambda type, and decl is not a member - of that type, then we have a reference to a member of 'this' from a + /* If decl is a non-capture field and object has a lambda type, + then we have a reference to a member of 'this' from a lambda inside a non-static member function, and we must get to decl through the 'this' capture. If decl is not a member of that object, either, then its access will still fail later. */ if (LAMBDA_TYPE_P (TREE_TYPE (object)) - && !same_type_ignoring_top_level_qualifiers_p (DECL_CONTEXT (decl), - TREE_TYPE (object))) + && !LAMBDA_TYPE_P (DECL_CONTEXT (decl))) object = cp_build_indirect_ref (lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (TREE_TYPE (object))), @@ -2063,17 +2063,13 @@ finish_this_expr (void) { tree result; - if (current_class_ptr) - { - tree type = TREE_TYPE (current_class_ref); - - /* In a lambda expression, 'this' refers to the captured 'this'. */ - if (LAMBDA_TYPE_P (type)) - result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type)); - else - result = current_class_ptr; - - } + /* In a lambda expression, 'this' refers to the captured 'this'. */ + if (current_function_decl + && LAMBDA_FUNCTION_P (current_function_decl)) + result = (lambda_expr_this_capture + (CLASSTYPE_LAMBDA_EXPR (current_class_type))); + else if (current_class_ptr) + result = current_class_ptr; else if (current_function_decl && DECL_STATIC_FUNCTION_P (current_function_decl)) { @@ -2648,6 +2644,18 @@ outer_automatic_var_p (tree decl) && DECL_CONTEXT (decl) != current_function_decl); } +/* Returns true iff DECL is a capture field from a lambda that is not our + immediate context. */ + +static bool +outer_lambda_capture_p (tree decl) +{ + return (TREE_CODE (decl) == FIELD_DECL + && LAMBDA_TYPE_P (DECL_CONTEXT (decl)) + && (!current_class_type + || !DERIVED_FROM_P (DECL_CONTEXT (decl), current_class_type))); +} + /* ID_EXPRESSION is a representation of parsed, but unprocessed, id-expression. (See cp_parser_id_expression for details.) SCOPE, if non-NULL, is the type or namespace used to explicitly qualify @@ -2751,7 +2759,8 @@ finish_id_expression (tree id_expression, /* Disallow uses of local variables from containing functions, except within lambda-expressions. */ - if (outer_automatic_var_p (decl) + if ((outer_automatic_var_p (decl) + || outer_lambda_capture_p (decl)) /* It's not a use (3.2) if we're in an unevaluated context. */ && !cp_unevaluated_operand) { @@ -2759,6 +2768,7 @@ finish_id_expression (tree id_expression, tree containing_function = current_function_decl; tree lambda_stack = NULL_TREE; tree lambda_expr = NULL_TREE; + tree initializer = decl; /* Core issue 696: "[At the July 2009 meeting] the CWG expressed support for an approach in which a reference to a local @@ -2770,6 +2780,13 @@ finish_id_expression (tree id_expression, if (DECL_INTEGRAL_CONSTANT_VAR_P (decl)) return integral_constant_value (decl); + if (TYPE_P (context)) + { + /* Implicit capture of an explicit capture. */ + context = lambda_function (context); + initializer = thisify_lambda_field (decl); + } + /* If we are in a lambda function, we can move out until we hit 1. the context, 2. a non-lambda function, or @@ -2796,7 +2813,7 @@ finish_id_expression (tree id_expression, { decl = add_default_capture (lambda_stack, /*id=*/DECL_NAME (decl), - /*initializer=*/decl); + initializer); } else if (lambda_expr) { @@ -4741,6 +4758,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) /* The type denoted by decltype(e) is defined as follows: */ + expr = resolve_nondeduced_context (expr); if (id_expression_or_member_access_p) { /* If e is an id-expression or a class member access (5.2.5 @@ -4766,9 +4784,13 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p) /* See through BASELINK nodes to the underlying functions. */ expr = BASELINK_FUNCTIONS (expr); + if (TREE_CODE (expr) == TEMPLATE_ID_EXPR) + expr = TREE_OPERAND (expr, 0); + if (TREE_CODE (expr) == OVERLOAD) { - if (OVL_CHAIN (expr)) + if (OVL_CHAIN (expr) + || TREE_CODE (OVL_FUNCTION (expr)) == TEMPLATE_DECL) { error ("%qE refers to a set of overloaded functions", orig_expr); return error_mark_node; @@ -5328,6 +5350,20 @@ build_lambda_object (tree lambda_expr) do some magic to make it work here. */ if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) val = build_array_copy (val); + else if (DECL_NORMAL_CAPTURE_P (field) + && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE) + { + /* "the entities that are captured by copy are used to + direct-initialize each corresponding non-static data + member of the resulting closure object." + + There's normally no way to express direct-initialization + from an element of a CONSTRUCTOR, so we build up a special + TARGET_EXPR to bypass the usual copy-initialization. */ + val = force_rvalue (val); + if (TREE_CODE (val) == TARGET_EXPR) + TARGET_EXPR_DIRECT_INIT_P (val) = true; + } CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val); } @@ -5545,7 +5581,8 @@ capture_decltype (tree decl) and return it. */ tree -add_capture (tree lambda, tree id, tree initializer, bool by_reference_p) +add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, + bool explicit_init_p) { tree type; tree member; @@ -5560,6 +5597,13 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p) /* Make member variable. */ member = build_lang_decl (FIELD_DECL, id, type); + if (!explicit_init_p) + /* Normal captures are invisible to name lookup but uses are replaced + with references to the capture field; we implement this by only + really making them invisible in unevaluated context; see + qualify_lookup. For now, let's make explicitly initialized captures + always visible. */ + DECL_NORMAL_CAPTURE_P (member) = true; /* Add it to the appropriate closure class. */ finish_member_declaration (member); @@ -5577,6 +5621,21 @@ add_capture (tree lambda, tree id, tree initializer, bool by_reference_p) return member; } +/* Given a FIELD_DECL decl belonging to a closure type, return a + COMPONENT_REF of it relative to the 'this' parameter of the op() for + that type. */ + +static tree +thisify_lambda_field (tree decl) +{ + tree context = lambda_function (DECL_CONTEXT (decl)); + tree object = cp_build_indirect_ref (DECL_ARGUMENTS (context), + /*errorstring*/"", + tf_warning_or_error); + return finish_non_static_data_member (decl, object, + /*qualifying_scope*/NULL_TREE); +} + /* Similar to add_capture, except this works on a stack of nested lambdas. BY_REFERENCE_P in this case is derived from the default capture mode. Returns the capture for the lambda at the bottom of the stack. */ @@ -5605,17 +5664,9 @@ add_default_capture (tree lambda_stack, tree id, tree initializer) /*by_reference_p=*/ (!this_capture_p && (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) - == CPLD_REFERENCE))); - - { - /* Have to get the old value of current_class_ref. */ - tree object = cp_build_indirect_ref (DECL_ARGUMENTS - (lambda_function (lambda)), - /*errorstring=*/"", - /*complain=*/tf_warning_or_error); - initializer = finish_non_static_data_member - (member, object, /*qualifying_scope=*/NULL_TREE); - } + == CPLD_REFERENCE)), + /*explicit_init_p=*/false); + initializer = thisify_lambda_field (member); } current_class_type = saved_class_type; @@ -5654,10 +5705,7 @@ lambda_expr_this_capture (tree lambda) { /* An outer lambda has already captured 'this'. */ tree cap = LAMBDA_EXPR_THIS_CAPTURE (lambda); - tree lthis - = cp_build_indirect_ref (DECL_ARGUMENTS (containing_function), - "", tf_warning_or_error); - init = finish_non_static_data_member (cap, lthis, NULL_TREE); + init = thisify_lambda_field (cap); break; } @@ -5707,4 +5755,55 @@ lambda_expr_this_capture (tree lambda) return result; } +/* If the closure TYPE has a static op(), also add a conversion to function + pointer. */ + +void +maybe_add_lambda_conv_op (tree type) +{ + bool nested = (current_function_decl != NULL_TREE); + tree callop = lambda_function (type); + tree rettype, name, fntype, fn, body, compound_stmt; + + if (!DECL_STATIC_FUNCTION_P (callop)) + return; + + rettype = build_pointer_type (TREE_TYPE (callop)); + name = mangle_conv_op_name_for_type (rettype); + fntype = build_function_type (rettype, void_list_node); + fn = build_lang_decl (FUNCTION_DECL, name, fntype); + DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); + + if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn + && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) + DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; + + SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); + grokclassfn (type, fn, NO_SPECIAL); + set_linkage_according_to_type (type, fn); + rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); + DECL_IN_AGGR_P (fn) = 1; + DECL_ARTIFICIAL (fn) = 1; + DECL_NOT_REALLY_EXTERN (fn) = 1; + DECL_DECLARED_INLINE_P (fn) = 1; + DECL_STATIC_FUNCTION_P (fn) = 1; + + add_method (type, fn, NULL_TREE); + + if (nested) + push_function_context (); + start_preparsed_function (fn, NULL_TREE, + SF_PRE_PARSED | SF_INCLASS_INLINE); + body = begin_function_body (); + compound_stmt = begin_compound_stmt (0); + + finish_return_stmt (decay_conversion (callop)); + + finish_compound_stmt (compound_stmt); + finish_function_body (body); + + expand_or_defer_fn (finish_function (2)); + if (nested) + pop_function_context (); +} #include "gt-cp-semantics.h" diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 1cd2bf596f8..5aea55e792f 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -946,6 +946,16 @@ cp_build_qualified_type_real (tree type, return result; } +/* Return TYPE with const and volatile removed. */ + +tree +cv_unqualified (tree type) +{ + int quals = TYPE_QUALS (type); + quals &= ~(TYPE_QUAL_CONST|TYPE_QUAL_VOLATILE); + return cp_build_qualified_type (type, quals); +} + /* Builds a qualified variant of T that is not a typedef variant. E.g. consider the following declarations: typedef const int ConstInt; @@ -1040,6 +1050,10 @@ strip_typedefs (tree t) else result = build_function_type (type, arg_types); + + if (TYPE_RAISES_EXCEPTIONS (t)) + result = build_exception_variant (result, + TYPE_RAISES_EXCEPTIONS (t)); } break; default: @@ -1048,6 +1062,8 @@ strip_typedefs (tree t) if (!result) result = TYPE_MAIN_VARIANT (t); + if (TYPE_ATTRIBUTES (t)) + result = cp_build_type_attribute_variant (result, TYPE_ATTRIBUTES (t)); return cp_build_qualified_type (result, cp_type_quals (t)); } @@ -1284,6 +1300,8 @@ build_qualified_name (tree type, tree scope, tree name, bool template_p) return error_mark_node; t = build2 (SCOPE_REF, type, scope, name); QUALIFIED_NAME_IS_TEMPLATE (t) = template_p; + if (type) + t = convert_from_reference (t); return t; } @@ -2079,6 +2097,8 @@ cp_tree_equal (tree t1, tree t2) case TEMPLATE_PARM_INDEX: return (TEMPLATE_PARM_IDX (t1) == TEMPLATE_PARM_IDX (t2) && TEMPLATE_PARM_LEVEL (t1) == TEMPLATE_PARM_LEVEL (t2) + && (TEMPLATE_PARM_PARAMETER_PACK (t1) + == TEMPLATE_PARM_PARAMETER_PACK (t2)) && same_type_p (TREE_TYPE (TEMPLATE_PARM_DECL (t1)), TREE_TYPE (TEMPLATE_PARM_DECL (t2)))); @@ -2595,7 +2615,8 @@ cp_build_type_attribute_variant (tree type, tree attributes) tree new_type; new_type = build_type_attribute_variant (type, attributes); - if (TREE_CODE (new_type) == FUNCTION_TYPE + if ((TREE_CODE (new_type) == FUNCTION_TYPE + || TREE_CODE (new_type) == METHOD_TYPE) && (TYPE_RAISES_EXCEPTIONS (new_type) != TYPE_RAISES_EXCEPTIONS (type))) new_type = build_exception_variant (new_type, @@ -3127,6 +3148,17 @@ cp_free_lang_data (tree t) DECL_EXTERNAL (t) = 1; TREE_STATIC (t) = 0; } + if (CP_AGGREGATE_TYPE_P (t) + && TYPE_NAME (t)) + { + tree name = TYPE_NAME (t); + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + /* Drop anonymous names. */ + if (name != NULL_TREE + && ANON_AGGRNAME_P (name)) + TYPE_NAME (t) = NULL_TREE; + } } diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index b4d54fc4089..7cafc8ab224 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1613,6 +1613,7 @@ decay_conversion (tree exp) if (type == error_mark_node) return error_mark_node; + exp = resolve_nondeduced_context (exp); if (type_unknown_p (exp)) { cxx_incomplete_type_error (exp, TREE_TYPE (exp)); @@ -1690,7 +1691,7 @@ decay_conversion (tree exp) Non-class rvalues always have cv-unqualified types. */ type = TREE_TYPE (exp); if (!CLASS_TYPE_P (type) && cp_type_quals (type)) - exp = build_nop (TYPE_MAIN_VARIANT (type), exp); + exp = build_nop (cv_unqualified (type), exp); return exp; } @@ -3244,6 +3245,7 @@ build_x_binary_op (enum tree_code code, tree arg1, enum tree_code arg1_code, misinterpret. But don't warn about obj << x + y, since that is a common idiom for I/O. */ if (warn_parentheses + && (complain & tf_warning) && !processing_template_decl && !error_operand_p (arg1) && !error_operand_p (arg2) @@ -5598,12 +5600,17 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p, intype, type); expr = cp_build_unary_op (ADDR_EXPR, expr, 0, complain); + + if (warn_strict_aliasing > 2) + strict_aliasing_warning (TREE_TYPE (expr), type, expr); + if (expr != error_mark_node) expr = build_reinterpret_cast_1 (build_pointer_type (TREE_TYPE (type)), expr, c_cast_p, valid_p, complain); if (expr != error_mark_node) - expr = cp_build_indirect_ref (expr, 0, complain); + /* cp_build_indirect_ref isn't right for rvalue refs. */ + expr = convert_from_reference (fold_convert (type, expr)); return expr; } @@ -6873,7 +6880,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags, if (fndecl) savew = warningcount, savee = errorcount; rhs = initialize_reference (type, rhs, /*decl=*/NULL_TREE, - /*cleanup=*/NULL); + /*cleanup=*/NULL, complain); if (fndecl) { if (warningcount > savew) @@ -6893,6 +6900,11 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags, type = complete_type (type); + if (DIRECT_INIT_EXPR_P (type, rhs)) + /* Don't try to do copy-initialization if we already have + direct-initialization. */ + return rhs; + if (MAYBE_CLASS_TYPE_P (type)) return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags); diff --git a/gcc/cse.c b/gcc/cse.c index 8f49a9af9f5..05f6ed6e0fe 100644 --- a/gcc/cse.c +++ b/gcc/cse.c @@ -2623,6 +2623,10 @@ exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse) if (GET_MODE (x) != GET_MODE (y)) return 0; + /* MEMs refering to different address space are not equivalent. */ + if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) + return 0; + switch (code) { case PC: diff --git a/gcc/cselib.c b/gcc/cselib.c index e6e5c143dad..0aa22a4fe1b 100644 --- a/gcc/cselib.c +++ b/gcc/cselib.c @@ -585,6 +585,7 @@ rtx_equal_for_cselib_p (rtx x, rtx y) { case CONST_DOUBLE: case CONST_FIXED: + case DEBUG_EXPR: return 0; case LABEL_REF: @@ -661,6 +662,19 @@ rtx_equal_for_cselib_p (rtx x, rtx y) return 1; } +/* We need to pass down the mode of constants through the hash table + functions. For that purpose, wrap them in a CONST of the appropriate + mode. */ +static rtx +wrap_constant (enum machine_mode mode, rtx x) +{ + if (!CONST_INT_P (x) && GET_CODE (x) != CONST_FIXED + && (GET_CODE (x) != CONST_DOUBLE || GET_MODE (x) != VOIDmode)) + return x; + gcc_assert (mode != VOIDmode); + return gen_rtx_CONST (mode, x); +} + /* Hash an rtx. Return 0 if we couldn't hash the rtx. For registers and memory locations, we look up their cselib_val structure and return its VALUE element. @@ -703,6 +717,11 @@ cselib_hash_rtx (rtx x, int create) return e->value; + case DEBUG_EXPR: + hash += ((unsigned) DEBUG_EXPR << 7) + + DEBUG_TEMP_UID (DEBUG_EXPR_TREE_DECL (x)); + return hash ? hash : (unsigned int) DEBUG_EXPR; + case CONST_INT: hash += ((unsigned) CONST_INT << 7) + INTVAL (x); return hash ? hash : (unsigned int) CONST_INT; @@ -1213,6 +1232,13 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, result = expand_loc (CSELIB_VAL_PTR (orig)->locs, evd, max_depth); return result; } + + case DEBUG_EXPR: + if (evd->callback) + return evd->callback (orig, evd->regs_active, max_depth, + evd->callback_arg); + return orig; + default: break; } @@ -1327,21 +1353,9 @@ cselib_expand_value_rtx_1 (rtx orig, struct expand_value_data *evd, default: break; } - if (scopy == NULL_RTX) - { - XEXP (copy, 0) - = gen_rtx_CONST (GET_MODE (XEXP (orig, 0)), XEXP (copy, 0)); - if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, " wrapping const_int result in const to preserve mode %s\n", - GET_MODE_NAME (GET_MODE (XEXP (copy, 0)))); - } scopy = simplify_rtx (copy); if (scopy) - { - if (GET_MODE (copy) != GET_MODE (scopy)) - scopy = wrap_constant (GET_MODE (copy), scopy); - return scopy; - } + return scopy; return copy; } @@ -1408,30 +1422,31 @@ cselib_subst_to_values (rtx x) { rtx t = cselib_subst_to_values (XEXP (x, i)); - if (t != XEXP (x, i) && x == copy) - copy = shallow_copy_rtx (x); - - XEXP (copy, i) = t; + if (t != XEXP (x, i)) + { + if (x == copy) + copy = shallow_copy_rtx (x); + XEXP (copy, i) = t; + } } else if (fmt[i] == 'E') { - int j, k; + int j; for (j = 0; j < XVECLEN (x, i); j++) { rtx t = cselib_subst_to_values (XVECEXP (x, i, j)); - if (t != XVECEXP (x, i, j) && XVEC (x, i) == XVEC (copy, i)) + if (t != XVECEXP (x, i, j)) { - if (x == copy) - copy = shallow_copy_rtx (x); - - XVEC (copy, i) = rtvec_alloc (XVECLEN (x, i)); - for (k = 0; k < j; k++) - XVECEXP (copy, i, k) = XVECEXP (x, i, k); + if (XVEC (x, i) == XVEC (copy, i)) + { + if (x == copy) + copy = shallow_copy_rtx (x); + XVEC (copy, i) = shallow_copy_rtvec (XVEC (x, i)); + } + XVECEXP (copy, i, j) = t; } - - XVECEXP (copy, i, j) = t; } } } @@ -1875,7 +1890,13 @@ cselib_record_sets (rtx insn) src = gen_rtx_IF_THEN_ELSE (GET_MODE (dest), cond, src, dest); sets[i].src_elt = cselib_lookup (src, GET_MODE (dest), 1); if (MEM_P (dest)) - sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), Pmode, 1); + { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (dest)); + + sets[i].dest_addr_elt = cselib_lookup (XEXP (dest, 0), + address_mode, 1); + } else sets[i].dest_addr_elt = 0; } diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 097b20be860..a7bae6003f6 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -346,6 +346,7 @@ const struct gcc_debug_hooks dbx_debug_hooks = { dbxout_init, dbxout_finish, + debug_nothing_void, debug_nothing_int_charstar, debug_nothing_int_charstar, dbxout_start_source_file, @@ -373,6 +374,10 @@ const struct gcc_debug_hooks dbx_debug_hooks = dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_rtx_rtx, /* copy_call_info */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; @@ -383,6 +388,7 @@ const struct gcc_debug_hooks xcoff_debug_hooks = { dbxout_init, dbxout_finish, + debug_nothing_void, debug_nothing_int_charstar, debug_nothing_int_charstar, dbxout_start_source_file, @@ -406,6 +412,10 @@ const struct gcc_debug_hooks xcoff_debug_hooks = dbxout_handle_pch, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_rtx_rtx, /* copy_call_info */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; @@ -3181,7 +3191,7 @@ dbxout_common_check (tree decl, int *value) rtx sym_addr; const char *name = NULL; - /* If the decl isn't a VAR_DECL, or if it isn't public or static, or if + /* If the decl isn't a VAR_DECL, or if it isn't static, or if it does not have a value (the offset into the common area), or if it is thread local (as opposed to global) then it isn't common, and shouldn't be handled as such. @@ -3190,7 +3200,6 @@ dbxout_common_check (tree decl, int *value) for thread-local symbols. Can be handled via same mechanism as used in dwarf2out.c. */ if (TREE_CODE (decl) != VAR_DECL - || !TREE_PUBLIC(decl) || !TREE_STATIC(decl) || !DECL_HAS_VALUE_EXPR_P(decl) || DECL_THREAD_LOCAL_P (decl) diff --git a/gcc/ddg.c b/gcc/ddg.c index 439acd1f434..c06ea75ea2d 100644 --- a/gcc/ddg.c +++ b/gcc/ddg.c @@ -167,7 +167,7 @@ create_ddg_dep_from_intra_loop_link (ddg_ptr g, ddg_node_ptr src_node, t = OUTPUT_DEP; gcc_assert (!DEBUG_INSN_P (dest_node->insn) || t == ANTI_DEP); - gcc_assert (!DEBUG_INSN_P (src_node->insn) || DEBUG_INSN_P (dest_node->insn)); + gcc_assert (!DEBUG_INSN_P (src_node->insn) || t == ANTI_DEP); /* We currently choose not to create certain anti-deps edges and compensate for that by generating reg-moves based on the life-range @@ -213,7 +213,7 @@ create_ddg_dep_no_link (ddg_ptr g, ddg_node_ptr from, ddg_node_ptr to, struct _dep _dep, *dep = &_dep; gcc_assert (!DEBUG_INSN_P (to->insn) || d_t == ANTI_DEP); - gcc_assert (!DEBUG_INSN_P (from->insn) || DEBUG_INSN_P (to->insn)); + gcc_assert (!DEBUG_INSN_P (from->insn) || d_t == ANTI_DEP); if (d_t == ANTI_DEP) dep_kind = REG_DEP_ANTI; diff --git a/gcc/debug.c b/gcc/debug.c index df69fd5eb82..c60a78d4708 100644 --- a/gcc/debug.c +++ b/gcc/debug.c @@ -27,6 +27,7 @@ const struct gcc_debug_hooks do_nothing_debug_hooks = { debug_nothing_charstar, debug_nothing_charstar, + debug_nothing_void, debug_nothing_int_charstar, debug_nothing_int_charstar, debug_nothing_int_charstar, @@ -50,6 +51,10 @@ const struct gcc_debug_hooks do_nothing_debug_hooks = debug_nothing_int, /* handle_pch */ debug_nothing_rtx, /* var_location */ debug_nothing_void, /* switch_text_section */ + debug_nothing_tree, /* direct_call */ + debug_nothing_tree_int, /* virtual_call_token */ + debug_nothing_rtx_rtx, /* copy_call_info */ + debug_nothing_uid, /* virtual_call */ debug_nothing_tree_tree, /* set_name */ 0 /* start_end_main_source_file */ }; @@ -92,6 +97,12 @@ debug_nothing_rtx (rtx insn ATTRIBUTE_UNUSED) { } +void +debug_nothing_rtx_rtx (rtx insn ATTRIBUTE_UNUSED, + rtx new_insn ATTRIBUTE_UNUSED) +{ +} + void debug_nothing_charstar (const char *main_filename ATTRIBUTE_UNUSED) { @@ -127,3 +138,8 @@ debug_nothing_tree_int (tree decl ATTRIBUTE_UNUSED, int local ATTRIBUTE_UNUSED) { } + +void +debug_nothing_uid (int uid ATTRIBUTE_UNUSED) +{ +} diff --git a/gcc/debug.h b/gcc/debug.h index de525fec2cd..079ecb623ad 100644 --- a/gcc/debug.h +++ b/gcc/debug.h @@ -31,6 +31,10 @@ struct gcc_debug_hooks /* Output debug symbols. */ void (* finish) (const char *main_filename); + /* Called from cgraph_optimize before starting to assemble + functions/variables/toplevel asms. */ + void (* assembly_start) (void); + /* Macro defined on line LINE with name and expansion TEXT. */ void (* define) (unsigned int line, const char *text); @@ -126,6 +130,31 @@ struct gcc_debug_hooks text sections. */ void (* switch_text_section) (void); + /* Records a direct call to the function DECL, noting the point of call + and the debug info for the function. Called from final_scan_insn + when ICF debugging is enabled. */ + void (* direct_call) (tree decl); + + /* Records the OBJ_TYPE_REF_TOKEN for a virtual call through ADDR, which + for C++ is the vtable slot index, noting the INSN_UID for the call + instruction. Called from calls.c:emit_call_1 when ICF debugging is + enabled. It's necessary to do this during lowering because the + call instruction and the OBJ_TYPE_REF become separated after that + point. */ + void (* virtual_call_token) (tree addr, int insn_uid); + + /* Copies the OBJ_TYPE_REF_TOKEN for a virtual call from OLD_INSN to + NEW_INSN. Called from emit-rtl.c:try_split when a CALL_INSN is + split, so that the vtable slot index remains associated with the + new CALL_INSN. */ + void (* copy_call_info) (rtx old_insn, rtx new_insn); + + /* Records a virtual call given INSN_UID, which is the UID of the call + instruction. The UID is then mapped to the vtable slot index noted + during the lowering phase. Called from final_scan_insn when ICF + debugging is enabled. */ + void (* virtual_call) (int insn_uid); + /* Called from grokdeclarator. Replaces the anonymous name with the type name. */ void (* set_name) (tree, tree); @@ -151,6 +180,8 @@ extern void debug_nothing_tree_int (tree, int); extern void debug_nothing_tree_tree_tree_bool (tree, tree, tree, bool); extern bool debug_true_const_tree (const_tree); extern void debug_nothing_rtx (rtx); +extern void debug_nothing_rtx_rtx (rtx, rtx); +extern void debug_nothing_uid (int); /* Hooks for various debug formats. */ extern const struct gcc_debug_hooks do_nothing_debug_hooks; diff --git a/gcc/defaults.h b/gcc/defaults.h index f1d96833070..182de95685c 100644 --- a/gcc/defaults.h +++ b/gcc/defaults.h @@ -1154,4 +1154,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #define GO_IF_MODE_DEPENDENT_ADDRESS(X, WIN) #endif +/* For most ports anything that evaluates to a constant symbolic + or integer value is acceptable as a constant address. */ +#ifndef CONSTANT_ADDRESS_P +#define CONSTANT_ADDRESS_P(X) (CONSTANT_P (X) && GET_CODE (X) != CONST_DOUBLE) +#endif + #endif /* ! GCC_DEFAULTS_H */ diff --git a/gcc/df-problems.c b/gcc/df-problems.c index cdbc8a19d9d..e9896e311d1 100644 --- a/gcc/df-problems.c +++ b/gcc/df-problems.c @@ -4026,10 +4026,6 @@ df_simulate_finalize_forwards (basic_block bb, bitmap live) propagating the information to BB3's successors. ---------------------------------------------------------------------------*/ -/* Scratch var used by transfer functions. This is used to do md analysis - only for live registers. */ -static bitmap df_md_scratch; - /* Set basic block info. */ static void @@ -4073,7 +4069,6 @@ df_md_alloc (bitmap all_blocks) sizeof (struct df_md_bb_info), 50); df_grow_bb_info (df_md); - df_md_scratch = BITMAP_ALLOC (NULL); EXECUTE_IF_SET_IN_BITMAP (all_blocks, 0, bb_index, bi) { @@ -4249,10 +4244,8 @@ df_md_local_compute (bitmap all_blocks) bitmap kill = df_md_get_bb_info (bb_index)->kill; EXECUTE_IF_SET_IN_BITMAP (frontiers[bb_index], 0, df_bb_index, bi2) { - basic_block bb = BASIC_BLOCK (df_bb_index); if (bitmap_bit_p (all_blocks, df_bb_index)) - bitmap_ior_and_into (df_md_get_bb_info (df_bb_index)->init, kill, - df_get_live_in (bb)); + bitmap_ior_into (df_md_get_bb_info (df_bb_index)->init, kill); } } @@ -4282,24 +4275,13 @@ df_md_reset (bitmap all_blocks) static bool df_md_transfer_function (int bb_index) { - basic_block bb = BASIC_BLOCK (bb_index); struct df_md_bb_info *bb_info = df_md_get_bb_info (bb_index); bitmap in = bb_info->in; bitmap out = bb_info->out; bitmap gen = bb_info->gen; bitmap kill = bb_info->kill; - /* We need to use a scratch set here so that the value returned from - this function invocation properly reflects if the sets changed in - a significant way; i.e. not just because the live set was anded - in. */ - bitmap_and (df_md_scratch, gen, df_get_live_out (bb)); - - /* Multiple definitions of a register are not relevant if it is not - used. Thus we trim the result to the places where it is live. */ - bitmap_and_into (in, df_get_live_in (bb)); - - return bitmap_ior_and_compl (out, df_md_scratch, in, kill); + return bitmap_ior_and_compl (out, gen, in, kill); } /* Initialize the solution bit vectors for problem. */ @@ -4362,7 +4344,6 @@ df_md_free (void) } } - BITMAP_FREE (df_md_scratch); free_alloc_pool (df_md->block_pool); df_md->block_info_size = 0; diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 45df29ecc2b..101234b55bc 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -3248,10 +3248,23 @@ df_uses_record (enum df_ref_class cl, struct df_collection_rec *collection_rec, width = INTVAL (XEXP (dst, 1)); offset = INTVAL (XEXP (dst, 2)); mode = GET_MODE (dst); - df_uses_record (DF_REF_EXTRACT, collection_rec, &XEXP (dst, 0), - DF_REF_REG_USE, bb, insn_info, - DF_REF_READ_WRITE | DF_REF_ZERO_EXTRACT, - width, offset, mode); + if (GET_CODE (XEXP (dst,0)) == MEM) + { + /* Handle the case of zero_extract(mem(...)) in the set dest. + This special case is allowed only if the mem is a single byte and + is useful to set a bitfield in memory. */ + df_uses_record (DF_REF_EXTRACT, collection_rec, &XEXP (XEXP (dst,0), 0), + DF_REF_REG_MEM_STORE, bb, insn_info, + DF_REF_ZERO_EXTRACT, + width, offset, mode); + } + else + { + df_uses_record (DF_REF_EXTRACT, collection_rec, &XEXP (dst, 0), + DF_REF_REG_USE, bb, insn_info, + DF_REF_READ_WRITE | DF_REF_ZERO_EXTRACT, + width, offset, mode); + } } else { diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi index d2d1673cc3b..ca86f28dd39 100644 --- a/gcc/doc/contrib.texi +++ b/gcc/doc/contrib.texi @@ -173,8 +173,8 @@ The @uref{http://www.gnu.org/software/classpath/,,GNU Classpath project} for all of their merged runtime code. @item -Nick Clifton for arm, mcore, fr30, v850, m32r work, @option{--help}, and -other random hacking. +Nick Clifton for arm, mcore, fr30, v850, m32r, rx work, +@option{--help}, and other random hacking. @item Michael Cook for libstdc++ cleanup patches to reduce warnings. diff --git a/gcc/doc/cpp.texi b/gcc/doc/cpp.texi index ce4c0c3ff5d..590630cee0d 100644 --- a/gcc/doc/cpp.texi +++ b/gcc/doc/cpp.texi @@ -3609,8 +3609,6 @@ These directives are not part of the C standard, but they are not official GNU extensions either. What historical information we have been able to find, suggests they originated with System V@. -Both @samp{#ident} and @samp{#sccs} are deprecated extensions. - @cindex null directive The @dfn{null directive} consists of a @samp{#} followed by a newline, with only whitespace (including comments) in between. A null directive diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 6f0955577c3..e09c9ee6685 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -39,6 +39,7 @@ extensions, accepted by GCC in C89 mode and in C++. * Decimal Float:: Decimal Floating Types. * Hex Floats:: Hexadecimal floating-point constants. * Fixed-Point:: Fixed-Point Types. +* Named Address Spaces::Named address spaces. * Zero Length:: Zero-length arrays. * Variable Length:: Arrays whose length is computed at run time. * Empty Structures:: Structures with no members. @@ -1197,6 +1198,31 @@ Pragmas to control overflow and rounding behaviors are not implemented. Fixed-point types are supported by the DWARF2 debug information format. +@node Named Address Spaces +@section Named address spaces +@cindex named address spaces + +As an extension, the GNU C compiler supports named address spaces as +defined in the N1275 draft of ISO/IEC DTR 18037. Support for named +address spaces in GCC will evolve as the draft technical report changes. +Calling conventions for any target might also change. At present, only +the SPU target supports other address spaces. On the SPU target, for +example, variables may be declared as belonging to another address space +by qualifying the type with the @code{__ea} address space identifier: + +@smallexample +extern int __ea i; +@end smallexample + +When the variable @code{i} is accessed, the compiler will generate +special code to access this variable. It may use runtime library +support, or generate special machine instructions to access that address +space. + +The @code{__ea} identifier may be used exactly like any other C type +qualifier (e.g., @code{const} or @code{volatile}). See the N1275 +document for more details. + @node Zero Length @section Arrays of Length Zero @cindex arrays of length zero @@ -2280,7 +2306,7 @@ addressing modes. @item fast_interrupt @cindex interrupt handler functions -Use this attribute on the M32C port to indicate that the specified +Use this attribute on the M32C and RX ports to indicate that the specified function is a fast interrupt handler. This is just like the @code{interrupt} attribute, except that @code{freit} is used to return instead of @code{reit}. @@ -2472,8 +2498,8 @@ This attribute is ignored for R8C target. @item interrupt @cindex interrupt handler functions -Use this attribute on the ARM, AVR, CRX, M32C, M32R/D, m68k, MeP, MIPS -and Xstormy16 ports to indicate that the specified function is an +Use this attribute on the ARM, AVR, CRX, M32C, M32R/D, m68k, MeP, MIPS, +RX and Xstormy16 ports to indicate that the specified function is an interrupt handler. The compiler will generate function entry and exit sequences suitable for use in an interrupt handler when this attribute is present. @@ -2679,9 +2705,17 @@ when targeting Windows. On all other systems, the default is the AMD ABI. Note, This feature is currently sorried out for Windows targets trying to +@item ms_hook_prologue +@cindex @code{ms_hook_prologue} attribute + +On 32 bit i[34567]86-*-* targets, you can use this function attribute to make +gcc generate the "hot-patching" function prologue used in Win32 API +functions in Microsoft Windows XP Service Pack 2 and newer. This requires +support for the swap suffix in the assembler. (GNU Binutils 2.19.51 or later) + @item naked @cindex function without a prologue/epilogue code -Use this attribute on the ARM, AVR, IP2K and SPU ports to indicate that +Use this attribute on the ARM, AVR, IP2K, RX and SPU ports to indicate that the specified function does not need prologue/epilogue sequences generated by the compiler. It is up to the programmer to provide these sequences. The only statements that can be safely included in naked functions are @@ -3173,6 +3207,16 @@ Enable/disable the generation of the SSE4A instructions. @cindex @code{target("fma4")} attribute Enable/disable the generation of the FMA4 instructions. +@item xop +@itemx no-xop +@cindex @code{target("xop")} attribute +Enable/disable the generation of the XOP instructions. + +@item lwp +@itemx no-lwp +@cindex @code{target("lwp")} attribute +Enable/disable the generation of the LWP instructions. + @item ssse3 @itemx no-ssse3 @cindex @code{target("ssse3")} attribute @@ -7452,6 +7496,7 @@ instructions, but allow the compiler to schedule those calls. * Other MIPS Built-in Functions:: * picoChip Built-in Functions:: * PowerPC AltiVec/VSX Built-in Functions:: +* RX Built-in Functions:: * SPARC VIS Built-in Functions:: * SPU Built-in Functions:: @end menu @@ -8893,6 +8938,134 @@ v2di __builtin_ia32_insertq (v2di, v2di) v2di __builtin_ia32_insertqi (v2di, v2di, const unsigned int, const unsigned int) @end smallexample +The following built-in functions are available when @option{-mxop} is used. +@smallexample +v2df __builtin_ia32_vfrczpd (v2df) +v4sf __builtin_ia32_vfrczps (v4sf) +v2df __builtin_ia32_vfrczsd (v2df, v2df) +v4sf __builtin_ia32_vfrczss (v4sf, v4sf) +v4df __builtin_ia32_vfrczpd256 (v4df) +v8sf __builtin_ia32_vfrczps256 (v8sf) +v2di __builtin_ia32_vpcmov (v2di, v2di, v2di) +v2di __builtin_ia32_vpcmov_v2di (v2di, v2di, v2di) +v4si __builtin_ia32_vpcmov_v4si (v4si, v4si, v4si) +v8hi __builtin_ia32_vpcmov_v8hi (v8hi, v8hi, v8hi) +v16qi __builtin_ia32_vpcmov_v16qi (v16qi, v16qi, v16qi) +v2df __builtin_ia32_vpcmov_v2df (v2df, v2df, v2df) +v4sf __builtin_ia32_vpcmov_v4sf (v4sf, v4sf, v4sf) +v4di __builtin_ia32_vpcmov_v4di256 (v4di, v4di, v4di) +v8si __builtin_ia32_vpcmov_v8si256 (v8si, v8si, v8si) +v16hi __builtin_ia32_vpcmov_v16hi256 (v16hi, v16hi, v16hi) +v32qi __builtin_ia32_vpcmov_v32qi256 (v32qi, v32qi, v32qi) +v4df __builtin_ia32_vpcmov_v4df256 (v4df, v4df, v4df) +v8sf __builtin_ia32_vpcmov_v8sf256 (v8sf, v8sf, v8sf) +v16qi __builtin_ia32_vpcomeqb (v16qi, v16qi) +v8hi __builtin_ia32_vpcomeqw (v8hi, v8hi) +v4si __builtin_ia32_vpcomeqd (v4si, v4si) +v2di __builtin_ia32_vpcomeqq (v2di, v2di) +v16qi __builtin_ia32_vpcomequb (v16qi, v16qi) +v4si __builtin_ia32_vpcomequd (v4si, v4si) +v2di __builtin_ia32_vpcomequq (v2di, v2di) +v8hi __builtin_ia32_vpcomequw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomeqw (v8hi, v8hi) +v16qi __builtin_ia32_vpcomfalseb (v16qi, v16qi) +v4si __builtin_ia32_vpcomfalsed (v4si, v4si) +v2di __builtin_ia32_vpcomfalseq (v2di, v2di) +v16qi __builtin_ia32_vpcomfalseub (v16qi, v16qi) +v4si __builtin_ia32_vpcomfalseud (v4si, v4si) +v2di __builtin_ia32_vpcomfalseuq (v2di, v2di) +v8hi __builtin_ia32_vpcomfalseuw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomfalsew (v8hi, v8hi) +v16qi __builtin_ia32_vpcomgeb (v16qi, v16qi) +v4si __builtin_ia32_vpcomged (v4si, v4si) +v2di __builtin_ia32_vpcomgeq (v2di, v2di) +v16qi __builtin_ia32_vpcomgeub (v16qi, v16qi) +v4si __builtin_ia32_vpcomgeud (v4si, v4si) +v2di __builtin_ia32_vpcomgeuq (v2di, v2di) +v8hi __builtin_ia32_vpcomgeuw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomgew (v8hi, v8hi) +v16qi __builtin_ia32_vpcomgtb (v16qi, v16qi) +v4si __builtin_ia32_vpcomgtd (v4si, v4si) +v2di __builtin_ia32_vpcomgtq (v2di, v2di) +v16qi __builtin_ia32_vpcomgtub (v16qi, v16qi) +v4si __builtin_ia32_vpcomgtud (v4si, v4si) +v2di __builtin_ia32_vpcomgtuq (v2di, v2di) +v8hi __builtin_ia32_vpcomgtuw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomgtw (v8hi, v8hi) +v16qi __builtin_ia32_vpcomleb (v16qi, v16qi) +v4si __builtin_ia32_vpcomled (v4si, v4si) +v2di __builtin_ia32_vpcomleq (v2di, v2di) +v16qi __builtin_ia32_vpcomleub (v16qi, v16qi) +v4si __builtin_ia32_vpcomleud (v4si, v4si) +v2di __builtin_ia32_vpcomleuq (v2di, v2di) +v8hi __builtin_ia32_vpcomleuw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomlew (v8hi, v8hi) +v16qi __builtin_ia32_vpcomltb (v16qi, v16qi) +v4si __builtin_ia32_vpcomltd (v4si, v4si) +v2di __builtin_ia32_vpcomltq (v2di, v2di) +v16qi __builtin_ia32_vpcomltub (v16qi, v16qi) +v4si __builtin_ia32_vpcomltud (v4si, v4si) +v2di __builtin_ia32_vpcomltuq (v2di, v2di) +v8hi __builtin_ia32_vpcomltuw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomltw (v8hi, v8hi) +v16qi __builtin_ia32_vpcomneb (v16qi, v16qi) +v4si __builtin_ia32_vpcomned (v4si, v4si) +v2di __builtin_ia32_vpcomneq (v2di, v2di) +v16qi __builtin_ia32_vpcomneub (v16qi, v16qi) +v4si __builtin_ia32_vpcomneud (v4si, v4si) +v2di __builtin_ia32_vpcomneuq (v2di, v2di) +v8hi __builtin_ia32_vpcomneuw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomnew (v8hi, v8hi) +v16qi __builtin_ia32_vpcomtrueb (v16qi, v16qi) +v4si __builtin_ia32_vpcomtrued (v4si, v4si) +v2di __builtin_ia32_vpcomtrueq (v2di, v2di) +v16qi __builtin_ia32_vpcomtrueub (v16qi, v16qi) +v4si __builtin_ia32_vpcomtrueud (v4si, v4si) +v2di __builtin_ia32_vpcomtrueuq (v2di, v2di) +v8hi __builtin_ia32_vpcomtrueuw (v8hi, v8hi) +v8hi __builtin_ia32_vpcomtruew (v8hi, v8hi) +v4si __builtin_ia32_vphaddbd (v16qi) +v2di __builtin_ia32_vphaddbq (v16qi) +v8hi __builtin_ia32_vphaddbw (v16qi) +v2di __builtin_ia32_vphadddq (v4si) +v4si __builtin_ia32_vphaddubd (v16qi) +v2di __builtin_ia32_vphaddubq (v16qi) +v8hi __builtin_ia32_vphaddubw (v16qi) +v2di __builtin_ia32_vphaddudq (v4si) +v4si __builtin_ia32_vphadduwd (v8hi) +v2di __builtin_ia32_vphadduwq (v8hi) +v4si __builtin_ia32_vphaddwd (v8hi) +v2di __builtin_ia32_vphaddwq (v8hi) +v8hi __builtin_ia32_vphsubbw (v16qi) +v2di __builtin_ia32_vphsubdq (v4si) +v4si __builtin_ia32_vphsubwd (v8hi) +v4si __builtin_ia32_vpmacsdd (v4si, v4si, v4si) +v2di __builtin_ia32_vpmacsdqh (v4si, v4si, v2di) +v2di __builtin_ia32_vpmacsdql (v4si, v4si, v2di) +v4si __builtin_ia32_vpmacssdd (v4si, v4si, v4si) +v2di __builtin_ia32_vpmacssdqh (v4si, v4si, v2di) +v2di __builtin_ia32_vpmacssdql (v4si, v4si, v2di) +v4si __builtin_ia32_vpmacsswd (v8hi, v8hi, v4si) +v8hi __builtin_ia32_vpmacssww (v8hi, v8hi, v8hi) +v4si __builtin_ia32_vpmacswd (v8hi, v8hi, v4si) +v8hi __builtin_ia32_vpmacsww (v8hi, v8hi, v8hi) +v4si __builtin_ia32_vpmadcsswd (v8hi, v8hi, v4si) +v4si __builtin_ia32_vpmadcswd (v8hi, v8hi, v4si) +v16qi __builtin_ia32_vpperm (v16qi, v16qi, v16qi) +v16qi __builtin_ia32_vprotb (v16qi, v16qi) +v4si __builtin_ia32_vprotd (v4si, v4si) +v2di __builtin_ia32_vprotq (v2di, v2di) +v8hi __builtin_ia32_vprotw (v8hi, v8hi) +v16qi __builtin_ia32_vpshab (v16qi, v16qi) +v4si __builtin_ia32_vpshad (v4si, v4si) +v2di __builtin_ia32_vpshaq (v2di, v2di) +v8hi __builtin_ia32_vpshaw (v8hi, v8hi) +v16qi __builtin_ia32_vpshlb (v16qi, v16qi) +v4si __builtin_ia32_vpshld (v4si, v4si) +v2di __builtin_ia32_vpshlq (v2di, v2di) +v8hi __builtin_ia32_vpshlw (v8hi, v8hi) +@end smallexample + The following built-in functions are available when @option{-mfma4} is used. All of them generate the machine instruction that is part of the name with MMX registers. @@ -8933,6 +9106,23 @@ v8sf __builtin_ia32_fmsubaddps256 (v8sf, v8sf, v8sf) @end smallexample +The following built-in functions are available when @option{-mlwp} is used. + +@smallexample +void __builtin_ia32_llwpcb16 (void *); +void __builtin_ia32_llwpcb32 (void *); +void __builtin_ia32_llwpcb64 (void *); +void * __builtin_ia32_llwpcb16 (void); +void * __builtin_ia32_llwpcb32 (void); +void * __builtin_ia32_llwpcb64 (void); +void __builtin_ia32_lwpval16 (unsigned short, unsigned int, unsigned short) +void __builtin_ia32_lwpval32 (unsigned int, unsigned int, unsigned int) +void __builtin_ia32_lwpval64 (unsigned __int64, unsigned int, unsigned int) +unsigned char __builtin_ia32_lwpins16 (unsigned short, unsigned int, unsigned short) +unsigned char __builtin_ia32_lwpins32 (unsigned int, unsigned int, unsigned int) +unsigned char __builtin_ia32_lwpins64 (unsigned __int64, unsigned int, unsigned int) +@end smallexample + The following built-in functions are available when @option{-m3dnow} is used. All of them generate the machine instruction that is part of the name. @@ -9732,7 +9922,7 @@ storing the value 32767 if the result overflows. @item int __builtin_subs (int @var{x}, int @var{y}) Saturating subtraction. Return the result of subtracting @var{y} from -@var{x}, storing the value -32768 if the result overflows. +@var{x}, storing the value @minus{}32768 if the result overflows. @item void __builtin_halt (void) Halt. The processor will stop execution. This built-in is useful for @@ -11746,6 +11936,121 @@ long __builtin_bpermd (long, long); int __builtin_bswap16 (int); @end smallexample +@node RX Built-in Functions +@subsection RX Built-in Functions +GCC supports some of the RX instructions which cannot be expressed in +the C programming language via the use of built-in functions. The +following functions are supported: + +@deftypefn {Built-in Function} void __builtin_rx_brk (void) +Generates the @code{brk} machine instruction. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_clrpsw (int) +Generates the @code{clrpsw} machine instruction to clear the specified +bit in the processor status word. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_int (int) +Generates the @code{int} machine instruction to generate an interrupt +with the specified value. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_machi (int, int) +Generates the @code{machi} machine instruction to add the result of +multiplying the top 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_maclo (int, int) +Generates the @code{maclo} machine instruction to add the result of +multiplying the bottom 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mulhi (int, int) +Generates the @code{mulhi} machine instruction to place the result of +multiplying the top 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mullo (int, int) +Generates the @code{mullo} machine instruction to place the result of +multiplying the bottom 16-bits of the two arguments into the +accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfachi (void) +Generates the @code{mvfachi} machine instruction to read the top +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfacmi (void) +Generates the @code{mvfacmi} machine instruction to read the middle +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_mvfc (int) +Generates the @code{mvfc} machine instruction which reads the control +register specified in its argument and returns its value. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtachi (int) +Generates the @code{mvtachi} machine instruction to set the top +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtaclo (int) +Generates the @code{mvtaclo} machine instruction to set the bottom +32-bits of the accumulator. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtc (int reg, int val) +Generates the @code{mvtc} machine instruction which sets control +register number @code{reg} to @code{val}. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_mvtipl (int) +Generates the @code{mvtipl} machine instruction set the interrupt +priority level. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_racw (int) +Generates the @code{racw} machine instruction to round the accumulator +according to the specified mode. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_revw (int) +Generates the @code{revw} machine instruction which swaps the bytes in +the argument so that bits 0--7 now occupy bits 8--15 and vice versa, +and also bits 16--23 occupy bits 24--31 and vice versa. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_rmpa (void) +Generates the @code{rmpa} machine instruction which initiates a +repeated multiply and accumulate sequence. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_round (float) +Generates the @code{round} machine instruction which returns the +floating point argument rounded according to the current rounding mode +set in the floating point status word register. +@end deftypefn + +@deftypefn {Built-in Function} int __builtin_rx_sat (int) +Generates the @code{sat} machine instruction which returns the +saturated value of the argument. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_setpsw (int) +Generates the @code{setpsw} machine instruction to set the specified +bit in the processor status word. +@end deftypefn + +@deftypefn {Built-in Function} void __builtin_rx_wait (void) +Generates the @code{wait} machine instruction. +@end deftypefn + @node SPARC VIS Built-in Functions @subsection SPARC VIS Built-in Functions @@ -11995,7 +12300,6 @@ extern int foo (); @end table - @node RS/6000 and PowerPC Pragmas @subsection RS/6000 and PowerPC Pragmas diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi index bfa336e2e9e..0fd68244ea7 100644 --- a/gcc/doc/install.texi +++ b/gcc/doc/install.texi @@ -356,6 +356,15 @@ Alternatively, if an MPC source distribution is found in a subdirectory of your GCC sources named @file{mpc}, it will be built together with GCC@. +@item libelf version 0.8.12 (or later) + +Necessary to build link-time optimization (LTO) support. It can be +downloaded from @uref{http://www.mr511.de/software/libelf-0.8.12.tar.gz}, +though it is commonly available in several systems. + +The @option{--with-libelf} configure option should be used if libelf is +not installed in your default library search patch. + @end table @heading Tools/packages necessary for modifying GCC @@ -1337,8 +1346,10 @@ powerpc-linux for powerpc64-linux, only generates 32-bit code. This option enables the 32-bit target to be a bi-arch compiler, which is useful when you want a bi-arch compiler that defaults to 32-bit, and you are building a bi-arch or multi-arch binutils in a combined tree. -Currently, this option only affects sparc-linux, powerpc-linux and -x86-linux. +On mips-linux, this will build a tri-arch compiler (ABI o32/n32/64), +defaulted to o32. +Currently, this option only affects sparc-linux, powerpc-linux, x86-linux +and mips-linux. @item --enable-secureplt This option enables @option{-msecure-plt} by default for powerpc-linux. @@ -1873,6 +1884,9 @@ not specified, then the Python modules are installed in $(prefix)/share/python. @item --enable-aot-compile-rpm Adds aot-compile-rpm to the list of installed scripts. +@item --enable-browser-plugin +Build the gcjwebplugin web browser plugin. + @table @code @item ansi Use the single-byte @code{char} and the Win32 A functions natively, @@ -1893,6 +1907,30 @@ Use the @code{WCHAR} and Win32 W functions natively. Does @emph{not} add @code{-lunicows} to @file{libgcj.spec}. The built executables will only run on Microsoft Windows NT and above. @end table + +@item --enable-lto +Enable support for link-time optimization (LTO). This is enabled by +default if a working libelf implementation is found (see +@option{--with-libelf}). + +@item --with-libelf=@var{pathname} +@itemx --with-libelf-include=@var{pathname} +@itemx --with-libelf-lib=@var{pathname} +If you do not have libelf installed in a standard location and you +want to enable support for link-time optimization (LTO), you can +explicitly specify the directory where libelf is installed +(@samp{--with-libelf=@var{libelfinstalldir}}). The +@option{--with-libelf=@var{libelfinstalldir}} option is shorthand for +@option{--with-libelf-include=@var{libelfinstalldir}/include} +@option{--with-libelf-lib=@var{libelfinstalldir}/lib}. + +@item --enable-gold +Enable support for using @command{gold} as the linker. If gold support is +enabled together with @option{--enable-lto}, an additional directory +@file{lto-plugin} will be built. The code in this directory is a +plugin for gold that allows the link-time optimizer to extract object +files with LTO information out of library archives. See +@option{-flto} and @option{-fwhopr} for details. @end table @subsubheading AWT-Specific Options @@ -2656,7 +2694,7 @@ incomplete or out of date. Send a note to @email{gcc@@gcc.gnu.org} detailing how the information should be changed. If you find a bug, please report it following the -@uref{../bugs.html,,bug reporting guidelines}. +@uref{../bugs/,,bug reporting guidelines}. If you want to print the GCC manuals, do @samp{cd @var{objdir}; make dvi}. You will need to have @command{texi2dvi} (version at least 4.7) @@ -3963,6 +4001,14 @@ the PSIM simulator. @heading @anchor{powerpcle-x-eabi}powerpcle-*-eabi Embedded PowerPC system in little endian mode. +@html +
+@end html +@heading @anchor{rx-x-elf}rx-*-elf +The Renesas RX processor. See +@uref{http://eu.renesas.com/fmwk.jsp?cnt=rx600_series_landing.jsp&fp=/products/mpumcu/rx_family/rx600_series} +for more information about this processor. + @html
@end html diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index e12241c97c1..20a9395f0b7 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -307,6 +307,7 @@ Objective-C and Objective-C++ Dialects}. -fcompare-debug@r{[}=@var{opts}@r{]} -fcompare-debug-second @gol -feliminate-dwarf2-dups -feliminate-unused-debug-types @gol -feliminate-unused-debug-symbols -femit-class-debug-always @gol +-fenable-icf-debug @gol -fmem-report -fpre-ipa-mem-report -fpost-ipa-mem-report -fprofile-arcs @gol -frandom-seed=@var{string} -fsched-verbose=@var{n} @gol -fsel-sched-verbose -fsel-sched-dump-cfg -fsel-sched-pipelining-verbose @gol @@ -320,7 +321,7 @@ Objective-C and Objective-C++ Dialects}. -femit-struct-debug-baseonly -femit-struct-debug-reduced @gol -femit-struct-debug-detailed@r{[}=@var{spec-list}@r{]} @gol -p -pg -print-file-name=@var{library} -print-libgcc-file-name @gol --print-multi-directory -print-multi-lib @gol +-print-multi-directory -print-multi-lib -print-multi-os-directory @gol -print-prog-name=@var{program} -print-search-dirs -Q @gol -print-sysroot -print-sysroot-headers-suffix @gol -save-temps -save-temps=cwd -save-temps=obj -time@r{[}=@var{file}@r{]}} @@ -345,12 +346,13 @@ Objective-C and Objective-C++ Dialects}. -finline-small-functions -fipa-cp -fipa-cp-clone -fipa-matrix-reorg -fipa-pta @gol -fipa-pure-const -fipa-reference -fipa-struct-reorg @gol -fipa-type-escape -fira-algorithm=@var{algorithm} @gol --fira-region=@var{region} -fira-coalesce -fno-ira-share-save-slots @gol +-fira-region=@var{region} -fira-coalesce @gol +-fira-loop-pressure -fno-ira-share-save-slots @gol -fno-ira-share-spill-slots -fira-verbose=@var{n} @gol -fivopts -fkeep-inline-functions -fkeep-static-consts @gol -floop-block -floop-interchange -floop-strip-mine -fgraphite-identity @gol --floop-parallelize-all @gol --fmerge-all-constants -fmerge-constants -fmodulo-sched @gol +-floop-parallelize-all -flto -flto-compression-level -flto-report -fltrans @gol +-fltrans-output-list -fmerge-all-constants -fmerge-constants -fmodulo-sched @gol -fmodulo-sched-allow-regmoves -fmove-loop-invariants -fmudflap @gol -fmudflapir -fmudflapth -fno-branch-count-reg -fno-default-inline @gol -fno-defer-pop -fno-function-cse -fno-guess-branch-probability @gol @@ -389,7 +391,7 @@ Objective-C and Objective-C++ Dialects}. -funit-at-a-time -funroll-all-loops -funroll-loops @gol -funsafe-loop-optimizations -funsafe-math-optimizations -funswitch-loops @gol -fvariable-expansion-in-unroller -fvect-cost-model -fvpt -fweb @gol --fwhole-program @gol +-fwhole-program -fwhopr -fwpa -fuse-linker-plugin @gol --param @var{name}=@var{value} -O -O0 -O1 -O2 -O3 -Os} @@ -471,7 +473,7 @@ Objective-C and Objective-C++ Dialects}. -mfix-cortex-m3-ldrd} @emph{AVR Options} -@gccoptlist{-mmcu=@var{mcu} -msize -mno-interrupts @gol +@gccoptlist{-mmcu=@var{mcu} -mno-interrupts @gol -mcall-prologues -mtiny-stack -mint8} @emph{Blackfin Options} @@ -592,7 +594,7 @@ Objective-C and Objective-C++ Dialects}. -mcld -mcx16 -msahf -mmovbe -mcrc32 -mrecip @gol -mmmx -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol -maes -mpclmul @gol --msse4a -m3dnow -mpopcnt -mabm -mfma4 @gol +-msse4a -m3dnow -mpopcnt -mabm -mfma4 -mxop -mlwp @gol -mthreads -mno-align-stringops -minline-all-stringops @gol -minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol -mpush-args -maccumulate-outgoing-args -m128bit-long-double @gol @@ -707,7 +709,7 @@ Objective-C and Objective-C++ Dialects}. -mbranch-cost=@var{num} -mbranch-likely -mno-branch-likely @gol -mfp-exceptions -mno-fp-exceptions @gol -mvr4130-align -mno-vr4130-align -msynci -mno-synci @gol --mrelax-pic-calls -mno-relax-pic-calls} +-mrelax-pic-calls -mno-relax-pic-calls -mmcount-ra-address} @emph{MMIX Options} @gccoptlist{-mlibfuncs -mno-libfuncs -mepsilon -mno-epsilon -mabi=gnu @gol @@ -781,6 +783,18 @@ See RS/6000 and PowerPC Options. -msim -mmvme -mads -myellowknife -memb -msdata @gol -msdata=@var{opt} -mvxworks -G @var{num} -pthread} +@emph{RX Options} +@gccoptlist{-m64bit-doubles -m32bit-doubles -fpu -nofpu@gol +-mcpu= -patch=@gol +-mbig-endian-data -mlittle-endian-data @gol +-msmall-data @gol +-msim -mno-sim@gol +-mas100-syntax -mno-as100-syntax@gol +-mrelax@gol +-mmax-constant-size=@gol +-mint-register=@gol +-msave-acc-in-interrupts} + @emph{S/390 and zSeries Options} @gccoptlist{-mtune=@var{cpu-type} -march=@var{cpu-type} @gol -mhard-float -msoft-float -mhard-dfp -mno-hard-dfp @gol @@ -834,7 +848,11 @@ See RS/6000 and PowerPC Options. -msafe-dma -munsafe-dma @gol -mbranch-hints @gol -msmall-mem -mlarge-mem -mstdmain @gol --mfixed-range=@var{register-range}} +-mfixed-range=@var{register-range} @gol +-mea32 -mea64 @gol +-maddress-space-conversion -mno-address-space-conversion @gol +-mcache-size=@var{cache-size} @gol +-matomic-updates -mno-atomic-updates} @emph{System V Options} @gccoptlist{-Qy -Qn -YP,@var{paths} -Ym,@var{dir}} @@ -861,7 +879,8 @@ See i386 and x86-64 Options. @emph{i386 and x86-64 Windows Options} @gccoptlist{-mconsole -mcygwin -mno-cygwin -mdll --mnop-fun-dllimport -mthread -municode -mwin32 -mwindows} +-mnop-fun-dllimport -mthread -municode -mwin32 -mwindows +-fno-set-stack-executable} @emph{Xstormy16 Options} @gccoptlist{-msim} @@ -4315,7 +4334,7 @@ minimum maximum, so we do not diagnose overlength strings in C++@. This option is implied by @option{-pedantic}, and can be disabled with @option{-Wno-overlength-strings}. -@item -Wunsuffixed-float-constants +@item -Wunsuffixed-float-constants @r{(C and Objective-C only)} @opindex Wunsuffixed-float-constants GCC will issue a warning for any floating constant that does not have @@ -4609,6 +4628,11 @@ The default is @samp{-femit-struct-debug-detailed=all}. This option works only with DWARF 2. +@item -fenable-icf-debug +@opindex fenable-icf-debug +Generate additional debug information to support identical code folding (ICF). +This option only works with DWARF version 2 or higher. + @item -fno-merge-debug-strings @opindex fmerge-debug-strings @opindex fno-merge-debug-strings @@ -5524,6 +5548,16 @@ that enable them. The directory name is separated from the switches by @samp{-}, without spaces between multiple switches. This is supposed to ease shell-processing. +@item -print-multi-os-directory +@opindex print-multi-os-directory +Print the path to OS libraries for the selected +multilib, relative to some @file{lib} subdirectory. If OS libraries are +present in the @file{lib} subdirectory and no multilibs are used, this is +usually just @file{.}, if OS libraries are present in @file{lib@var{suffix}} +sibling directories this prints e.g.@: @file{../lib64}, @file{../lib} or +@file{../lib32}, or if OS libraries are present in @file{lib/@var{subdir}} +subdirectories it prints e.g.@: @file{amd64}, @file{sparcv9} or @file{ev6}. + @item -print-prog-name=@var{program} @opindex print-prog-name Like @option{-print-file-name}, but searches for a program such as @samp{cpp}. @@ -5621,6 +5655,9 @@ each of them. Not all optimizations are controlled directly by a flag. Only optimizations that have a flag are listed in this section. +Most of the optimizations are not enabled if a @option{-O} level is not set on +the command line, even if individual optimization flags are specified. + Depending on the target and how GCC was configured, a slightly different set of optimizations may be enabled at each @option{-O} level than those listed here. You can invoke GCC with @samp{-Q --help=optimizers} @@ -6210,6 +6247,15 @@ give the best results in most cases and for most architectures. Do optimistic register coalescing. This option might be profitable for architectures with big regular register files. +@item -fira-loop-pressure +@opindex fira-loop-pressure +Use IRA to evaluate register pressure in loops for decision to move +loop invariants. Usage of this option usually results in generation +of faster and smaller code on machines with big register files (>= 32 +registers) but it can slow compiler down. + +This option is enabled at level @option{-O3} for some targets. + @item -fno-ira-share-save-slots @opindex fno-ira-share-save-slots Switch off sharing stack slots used for saving call used hard @@ -7105,12 +7151,237 @@ and those merged by attribute @code{externally_visible} become static functions and in effect are optimized more aggressively by interprocedural optimizers. While this option is equivalent to proper use of the @code{static} keyword for programs consisting of a single file, in combination with option -@option{--combine} this flag can be used to compile many smaller scale C -programs since the functions and variables become local for the whole combined -compilation unit, not for the single source file itself. +@option{-combine}, @option{-flto} or @option{-fwhopr} this flag can be used to +compile many smaller scale programs since the functions and variables become +local for the whole combined compilation unit, not for the single source file +itself. This option implies @option{-fwhole-file} for Fortran programs. +@item -flto +@opindex flto +This option runs the standard link-time optimizer. When invoked +with source code, it generates GIMPLE (one of GCC's internal +representations) and writes it to special ELF sections in the object +file. When the object files are linked together, all the function +bodies are read from these ELF sections and instantiated as if they +had been part of the same translation unit. + +To use the link-timer optimizer, @option{-flto} needs to be specified at +compile time and during the final link. For example, + +@smallexample +gcc -c -O2 -flto foo.c +gcc -c -O2 -flto bar.c +gcc -o myprog -flto -O2 foo.o bar.o +@end smallexample + +The first two invocations to GCC will save a bytecode representation +of GIMPLE into special ELF sections inside @file{foo.o} and +@file{bar.o}. The final invocation will read the GIMPLE bytecode from +@file{foo.o} and @file{bar.o}, merge the two files into a single +internal image, and compile the result as usual. Since both +@file{foo.o} and @file{bar.o} are merged into a single image, this +causes all the inter-procedural analyses and optimizations in GCC to +work across the two files as if they were a single one. This means, +for example, that the inliner will be able to inline functions in +@file{bar.o} into functions in @file{foo.o} and vice-versa. + +Another (simpler) way to enable link-time optimization is, + +@smallexample +gcc -o myprog -flto -O2 foo.c bar.c +@end smallexample + +The above will generate bytecode for @file{foo.c} and @file{bar.c}, +merge them together into a single GIMPLE representation and optimize +them as usual to produce @file{myprog}. + +The only important thing to keep in mind is that to enable link-time +optimizations the @option{-flto} flag needs to be passed to both the +compile and the link commands. + +Note that when a file is compiled with @option{-flto}, the generated +object file will be larger than a regular object file because it will +contain GIMPLE bytecodes and the usual final code. This means that +object files with LTO information can be linked as a normal object +file. So, in the previous example, if the final link is done with + +@smallexample +gcc -o myprog foo.o bar.o +@end smallexample + +The only difference will be that no inter-procedural optimizations +will be applied to produce @file{myprog}. The two object files +@file{foo.o} and @file{bar.o} will be simply sent to the regular +linker. + +Additionally, the optimization flags used to compile individual files +are not necessarily related to those used at link-time. For instance, + +@smallexample +gcc -c -O0 -flto foo.c +gcc -c -O0 -flto bar.c +gcc -o myprog -flto -O3 foo.o bar.o +@end smallexample + +This will produce individual object files with unoptimized assembler +code, but the resulting binary @file{myprog} will be optimized at +@option{-O3}. Now, if the final binary is generated without +@option{-flto}, then @file{myprog} will not be optimized. + +When producing the final binary with @option{-flto}, GCC will only +apply link-time optimizations to those files that contain bytecode. +Therefore, you can mix and match object files and libraries with +GIMPLE bytecodes and final object code. GCC will automatically select +which files to optimize in LTO mode and which files to link without +further processing. + +There are some code generation flags that GCC will preserve when +generating bytecodes, as they need to be used during the final link +stage. Currently, the following options are saved into the GIMPLE +bytecode files: @option{-fPIC}, @option{-fcommon} and all the +@option{-m} target flags. + +At link time, these options are read-in and reapplied. Note that the +current implementation makes no attempt at recognizing conflicting +values for these options. If two or more files have a conflicting +value (e.g., one file is compiled with @option{-fPIC} and another +isn't), the compiler will simply use the last value read from the +bytecode files. It is recommended, then, that all the files +participating in the same link be compiled with the same options. + +Another feature of LTO is that it is possible to apply interprocedural +optimizations on files written in different languages. This requires +some support in the language front end. Currently, the C, C++ and +Fortran front ends are capable of emitting GIMPLE bytecodes, so +something like this should work + +@smallexample +gcc -c -flto foo.c +g++ -c -flto bar.cc +gfortran -c -flto baz.f90 +g++ -o myprog -flto -O3 foo.o bar.o baz.o -lgfortran +@end smallexample + +Notice that the final link is done with @command{g++} to get the C++ +runtime libraries and @option{-lgfortran} is added to get the Fortran +runtime libraries. In general, when mixing languages in LTO mode, you +should use the same link command used when mixing languages in a +regular (non-LTO) compilation. This means that if your build process +was mixing languages before, all you need to add is @option{-flto} to +all the compile and link commands. + +If object files containing GIMPLE bytecode are stored in a library +archive, say @file{libfoo.a}, it is possible to extract and use them +in an LTO link if you are using @command{gold} as the linker (which, +in turn requires GCC to be configured with @option{--enable-gold}). +To enable this feature, use the flag @option{-fuse-linker-plugin} at +link-time: + +@smallexample +gcc -o myprog -O2 -flto -fuse-linker-plugin a.o b.o -lfoo +@end smallexample + +With the linker plugin enabled, @command{gold} will extract the needed +GIMPLE files from @file{libfoo.a} and pass them on to the running GCC +to make them part of the aggregated GIMPLE image to be optimized. + +If you are not using @command{gold} and/or do not specify +@option{-fuse-linker-plugin} then the objects inside @file{libfoo.a} +will be extracted and linked as usual, but they will not participate +in the LTO optimization process. + +Link time optimizations do not require the presence of the whole +program to operate. If the program does not require any symbols to +be exported, it is possible to combine @option{-flto} and +@option{-fwhopr} with @option{-fwhole-program} to allow the +interprocedural optimizers to use more aggressive assumptions which +may lead to improved optimization opportunities. + +Regarding portability: the current implementation of LTO makes no +attempt at generating bytecode that can be ported between different +types of hosts. The bytecode files are versioned and there is a +strict version check, so bytecode files generated in one version of +GCC will not work with an older/newer version of GCC. + +This option is disabled by default. + +@item -fwhopr +@opindex fwhopr +This option is identical in functionality to @option{-flto} but it +differs in how the final link stage is executed. Instead of loading +all the function bodies in memory, the callgraph is analyzed and +optimization decisions are made (whole program analysis or WPA). Once +optimization decisions are made, the callgraph is partitioned and the +different sections are compiled separately (local transformations or +LTRANS)@. This process allows optimizations on very large programs +that otherwise would not fit in memory. This option enables +@option{-fwpa} and @option{-fltrans} automatically. + +Disabled by default. + +@item -fwpa +@opindex fwpa +This is an internal option used by GCC when compiling with +@option{-fwhopr}. You should never need to use it. + +This option runs the link-time optimizer in the whole-program-analysis +(WPA) mode, which reads in summary information from all inputs and +performs a whole-program analysis based on summary information only. +It generates object files for subsequent runs of the link-time +optimizer where individual object files are optimized using both +summary information from the WPA mode and the actual function bodies. +It then drives the LTRANS phase. + +Disabled by default. + +@item -fltrans +@opindex fltrans +This is an internal option used by GCC when compiling with +@option{-fwhopr}. You should never need to use it. + +This option runs the link-time optimizer in the local-transformation (LTRANS) +mode, which reads in output from a previous run of the LTO in WPA mode. +In the LTRANS mode, LTO optimizes an object and produces the final assembly. + +Disabled by default. + +@item -fltrans-output-list=@var{file} +@opindex fltrans-output-list +This is an internal option used by GCC when compiling with +@option{-fwhopr}. You should never need to use it. + +This option specifies a file to which the names of LTRANS output files are +written. This option is only meaningful in conjunction with @option{-fwpa}. + +Disabled by default. + +@item -flto-compression-level=@var{n} +This option specifies the level of compression used for intermediate +language written to LTO object files, and is only meaningful in +conjunction with LTO mode (@option{-fwhopr}, @option{-flto}). Valid +values are 0 (no compression) to 9 (maximum compression). Values +outside this range are clamped to either 0 or 9. If the option is not +given, a default balanced compression setting is used. + +@item -flto-report +Prints a report with internal details on the workings of the link-time +optimizer. The contents of this report vary from version to version, +it is meant to be useful to GCC developers when processing object +files in LTO mode (via @option{-fwhopr} or @option{-flto}). + +Disabled by default. + +@item -fuse-linker-plugin +Enables the extraction of objects with GIMPLE bytecode information +from library archives. This option relies on features available only +in @command{gold}, so to use this you must configure GCC with +@option{--enable-gold}. See @option{-flto} for a description on the +effect of this flag and how to use it. + +Disabled by default. + @item -fcprop-registers @opindex fcprop-registers After register allocation and post-register allocation instruction splitting, @@ -8156,6 +8427,14 @@ lower quality register allocation algorithm will be used. The algorithm do not use pseudo-register conflicts. The default value of the parameter is 2000. +@item ira-loop-reserved-regs +IRA can be used to evaluate more accurate register pressure in loops +for decision to move loop invariants (see @option{-O3}). The number +of available registers reserved for some other purposes is described +by this parameter. The default value of the parameter is 2 which is +minimal number of registers needed for execution of typical +instruction. This value is the best found from numerous experiments. + @item loop-invariant-max-bbs-in-loop Loop invariant motion can be very expensive, both in compile time and in amount of needed compile time memory, with very large loops. Loops @@ -9268,6 +9547,7 @@ platform. * picoChip Options:: * PowerPC Options:: * RS/6000 and PowerPC Options:: +* RX Options:: * S/390 and zSeries Options:: * Score Options:: * SH Options:: @@ -9706,10 +9986,6 @@ Instruction set avr5 is for the enhanced AVR core with up to 128K program memory space (MCU types: atmega16, atmega161, atmega163, atmega32, atmega323, atmega64, atmega128, at43usb355, at94k). -@item -msize -@opindex msize -Output instruction sizes to the asm file. - @item -mno-interrupts @opindex mno-interrupts Generated code is not compatible with hardware interrupts. @@ -10685,7 +10961,7 @@ These @samp{-m} options are defined for the DEC Alpha/VMS implementations: @table @gcctabopt @item -mvms-return-codes @opindex mvms-return-codes -Return VMS condition codes from main. The default is to return POSIX +Return VMS condition codes from main. The default is to return POSIX style condition (e.g.@: error) codes. @item -mdebug-main=@var{prefix} @@ -11729,6 +12005,10 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}. @itemx -mno-sse4a @itemx -mfma4 @itemx -mno-fma4 +@itemx -mxop +@itemx -mno-xop +@itemx -mlwp +@itemx -mno-lwp @itemx -m3dnow @itemx -mno-3dnow @itemx -mpopcnt @@ -11742,8 +12022,8 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}. @opindex m3dnow @opindex mno-3dnow These switches enable or disable the use of instructions in the MMX, -SSE, SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, SSE4A, FMA4, ABM or -3DNow!@: extended instruction sets. +SSE, SSE2, SSE3, SSSE3, SSE4.1, AVX, AES, PCLMUL, SSE4A, FMA4, XOP, +LWP, ABM or 3DNow!@: extended instruction sets. These extensions are also available as built-in functions: see @ref{X86 Built-in Functions}, for details of the functions enabled and disabled by these switches. @@ -11816,6 +12096,10 @@ Note that while the throughput of the sequence is higher than the throughput of the non-reciprocal instruction, the precision of the sequence can be decreased by up to 2 ulp (i.e. the inverse of 1.0 equals 0.99999994). +Note that GCC implements 1.0f/sqrtf(x) in terms of RSQRTSS (or RSQRTPS) +already with @option{-ffast-math} (or the above option combination), and +doesn't need @option{-mrecip}. + @item -mveclibabi=@var{type} @opindex mveclibabi Specifies the ABI type to use for vectorizing intrinsics using an @@ -13934,6 +14218,27 @@ an assembler and a linker that supports the @code{.reloc} assembly directive and @code{-mexplicit-relocs} is in effect. With @code{-mno-explicit-relocs}, this optimization can be performed by the assembler and the linker alone without help from the compiler. + +@item -mmcount-ra-address +@itemx -mno-mcount-ra-address +@opindex mmcount-ra-address +@opindex mno-mcount-ra-address +Emit (do not emit) code that allows @code{_mcount} to modify the +calling function's return address. When enabled, this option extends +the usual @code{_mcount} interface with a new @var{ra-address} +parameter, which has type @code{intptr_t *} and is passed in register +@code{$12}. @code{_mcount} can then modify the return address by +doing both of the following: +@itemize +@item +Returning the new address in register @code{$31}. +@item +Storing the new address in @code{*@var{ra-address}}, +if @var{ra-address} is nonnull. +@end itemize + +The default is @option{-mno-mcount-ra-address}. + @end table @node MMIX Options @@ -14379,11 +14684,11 @@ Set architecture type, register usage, choice of mnemonics, and instruction scheduling parameters for machine type @var{cpu_type}. Supported values for @var{cpu_type} are @samp{401}, @samp{403}, @samp{405}, @samp{405fp}, @samp{440}, @samp{440fp}, @samp{464}, @samp{464fp}, -@samp{505}, @samp{601}, @samp{602}, @samp{603}, @samp{603e}, @samp{604}, -@samp{604e}, @samp{620}, @samp{630}, @samp{740}, @samp{7400}, -@samp{7450}, @samp{750}, @samp{801}, @samp{821}, @samp{823}, -@samp{860}, @samp{970}, @samp{8540}, @samp{e300c2}, @samp{e300c3}, -@samp{e500mc}, @samp{ec603e}, @samp{G3}, @samp{G4}, @samp{G5}, +@samp{476}, @samp{476fp}, @samp{505}, @samp{601}, @samp{602}, @samp{603}, +@samp{603e}, @samp{604}, @samp{604e}, @samp{620}, @samp{630}, @samp{740}, +@samp{7400}, @samp{7450}, @samp{750}, @samp{801}, @samp{821}, @samp{823}, +@samp{860}, @samp{970}, @samp{8540}, @samp{a2}, @samp{e300c2}, +@samp{e300c3}, @samp{e500mc}, @samp{ec603e}, @samp{G3}, @samp{G4}, @samp{G5}, @samp{power}, @samp{power2}, @samp{power3}, @samp{power4}, @samp{power5}, @samp{power5+}, @samp{power6}, @samp{power6x}, @samp{power7}, @samp{common}, @samp{powerpc}, @samp{powerpc64}, @samp{rios}, @@ -14727,7 +15032,7 @@ hardware floating is used. @opindex mmulhw @opindex mno-mulhw Generate code that uses (does not use) the half-word multiply and -multiply-accumulate instructions on the IBM 405, 440 and 464 processors. +multiply-accumulate instructions on the IBM 405, 440, 464 and 476 processors. These instructions are generated by default when targetting those processors. @@ -14736,7 +15041,7 @@ processors. @opindex mdlmzb @opindex mno-dlmzb Generate code that uses (does not use) the string-search @samp{dlmzb} -instruction on the IBM 405, 440 and 464 processors. This instruction is +instruction on the IBM 405, 440, 464 and 476 processors. This instruction is generated by default when targetting those processors. @item -mno-bit-align @@ -15104,6 +15409,142 @@ This option sets flags for both the preprocessor and linker. @end table +@node RX Options +@subsection RX Options +@cindex RX Options + +These @option{-m} options are defined for RX implementations: + +@table @gcctabopt +@item -m64bit-doubles +@itemx -m32bit-doubles +@itemx -fpu +@itemx -nofpu +@opindex m64bit-doubles +@opindex m32bit-doubles +@opindex fpu +@opindex nofpu +Make the @code{double} data type be 64-bits (@option{-m64bit-doubles}) +or 32-bits (@option{-m32bit-doubles}) in size. The default is +@option{-m64bit-doubles}. @emph{Note} the RX's hardware floating +point instructions are only used for 32-bit floating point values, and +then only if @option{-ffast-math} has been specified on the command +line. This is because the RX FPU instructions do not properly support +denormal (or sub-normal) values. + +The options @option{-fpu} and @option{-nofpu} have been provided at +the request of Rensas for compatibility with their toolchain. The +@option{-mfpu} option enables the use of RX FPU instructions by +selecting 32-bit doubles and enabling unsafe math optimizations. The +@option{-mnofpu} option disables the use of RX FPU instructions, even +if @option{-m32bit-doubles} is active and unsafe math optimizations +have been enabled. + +@item -mcpu=@var{name} +@itemx -patch=@var{name} +@opindex -mcpu +@opindex -patch +Selects the type of RX CPU to be targeted. Currently on two types are +supported, the generic @var{RX600} and the specific @var{RX610}. The +only difference between them is that the @var{RX610} does not support +the @code{MVTIPL} instruction. + +@item -mbig-endian-data +@itemx -mlittle-endian-data +@opindex mbig-endian-data +@opindex mlittle-endian-data +Store data (but not code) in the big-endian format. The default is +@option{-mlittle-endian-data}, ie to store data in the little endian +format. + +@item -msmall-data-limit=@var{N} +@opindex msmall-data-limit +Specifies the maximum size in bytes of global and static variables +which can be placed into the small data area. Using the small data +area can lead to smaller and faster code, but the size of area is +limited and it is up to the programmer to ensure that the area does +not overflow. Also when the small data area is used one of the RX's +registers (@code{r13}) is reserved for use pointing to this area, so +it is no longer available for use by the compiler. This could result +in slower and/or larger code if variables which once could have been +held in @code{r13} are now pushed onto the stack. + +Note, common variables (variables which have not been initialised) and +constants are not placed into the small data area as they are assigned +to other sections in the output executeable. + +The default value is zero, which disables this feature. Note, this +feature is not enabled by default with higher optimization levels +(@option{-O2} etc) because of the potentially deterimental effects of +reserving register @code{r13}. It is up to the programmer to +experiment and discover whether this feature is of benefit to their +program. + +@item -msim +@item -mno-sim +@opindex msim +@opindex mno-sim +Use the simulator runtime. The default is to use the libgloss board +specific runtime. + +@item -mas100-syntax +@item -mno-as100-syntax +@opindex mas100-syntax +@opindex mno-as100-syntax +When generating assembler output use a syntax that is compatible with +Renesas's AS100 assembler. This syntax can also be handled by the GAS +assembler but it has some restrictions so generating it is not the +default option. + +@item -mmax-constant-size=@var{N} +@opindex mmax-constant-size +Specifies the maxium size, in bytes, of a constant that can be used as +an operand in a RX instruction. Although the RX instruction set does +allow consants of up to 4 bytes in length to be used in instructions, +a longer value equates to a longer instruction. Thus in some +circumstances it can be beneficial to restrict the size of constants +that are used in instructions. Constants that are too big are instead +placed into a constant pool and referenced via register indirection. + +The value @var{N} can be between 0 and 3. A value of 0, the default, +means that constants of any size are allowed. + +@item -mrelax +@opindex mrelax +Enable linker relaxation. Linker relaxation is a process whereby the +linker will attempt to reduce the size of a program by finding shorter +versions of various instructions. Disabled by default. + +@item -mint-register=@var{N} +@opindex mint-register +Specify the number of registers to reserve for fast interrupt handler +functions. The value @var{N} can be between 0 and 4. A value of 1 +means that register @code{r13} will be reserved for ther exclusive use +of fast interrupt handlers. A value of 2 reserves @code{r13} and +@code{r12}. A value of 3 reserves @code{r13}, @code{r12} and +@code{r11}, and a value of 4 reserves @code{r13} through @code{r10}. +A value of 0, the default, does not reserve any registers. + +@item -msave-acc-in-interrupts +@opindex msave-acc-in-interrupts +Specifies that interrupt handler functions should preserve the +accumulator register. This is only necessary if normal code might use +the accumulator register, for example because it performs 64-bit +multiplications. The default is to ignore the accumulator as this +makes the interrupt handlers faster. + +@end table + +@emph{Note:} The generic GCC command line @option{-ffixed-@var{reg}} +has special significance to the RX port when used with the +@code{interrupt} function attribute. This attribute indicates a +function intended to process fast interrupts. GCC will will ensure +that it only uses the registers @code{r10}, @code{r11}, @code{r12} +and/or @code{r13} and only provided that the normal use of the +corresponding registers have been restricted via the +@option{-ffixed-@var{reg}} or @option{-mint-register} command line +options. + @node S/390 and zSeries Options @subsection S/390 and zSeries Options @cindex S/390 and zSeries Options @@ -15983,6 +16424,46 @@ useful when compiling kernel code. A register range is specified as two registers separated by a dash. Multiple register ranges can be specified separated by a comma. +@item -mea32 +@itemx -mea64 +@opindex mea32 +@opindex mea64 +Compile code assuming that pointers to the PPU address space accessed +via the @code{__ea} named address space qualifier are either 32 or 64 +bits wide. The default is 32 bits. As this is an ABI changing option, +all object code in an executable must be compiled with the same setting. + +@item -maddress-space-conversion +@itemx -mno-address-space-conversion +@opindex maddress-space-conversion +@opindex mno-address-space-conversion +Allow/disallow treating the @code{__ea} address space as superset +of the generic address space. This enables explicit type casts +between @code{__ea} and generic pointer as well as implicit +conversions of generic pointers to @code{__ea} pointers. The +default is to allow address space pointer conversions. + +@item -mcache-size=@var{cache-size} +@opindex mcache-size +This option controls the version of libgcc that the compiler links to an +executable and selects a software-managed cache for accessing variables +in the @code{__ea} address space with a particular cache size. Possible +options for @var{cache-size} are @samp{8}, @samp{16}, @samp{32}, @samp{64} +and @samp{128}. The default cache size is 64KB. + +@item -matomic-updates +@itemx -mno-atomic-updates +@opindex matomic-updates +@opindex mno-atomic-updates +This option controls the version of libgcc that the compiler links to an +executable and selects whether atomic updates to the software-managed +cache of PPU-side variables are used. If you use atomic updates, changes +to a PPU variable from SPU code using the @code{__ea} named address space +qualifier will not interfere with changes to other PPU variables residing +in the same cache line from PPU code. If you do not use atomic updates, +such interference may occur; however, writing back cache lines will be +more efficient. The default behavior is to use atomic updates. + @item -mdual-nops @itemx -mdual-nops=@var{n} @opindex mdual-nops @@ -16285,6 +16766,14 @@ specifies that a GUI application is to be generated by instructing the linker to set the PE header subsystem type appropriately. +@item -fno-set-stack-executable +@opindex fno-set-stack-executable +This option is available for MinGW targets. It specifies that +the executable flag for stack used by nested functions isn't +set. This is necessary for binaries running in kernel mode of +Windows, as there the user32 API, which is used to set executable +privileges, isn't available. + @item -mpe-aligned-commons @opindex mpe-aligned-commons This option is available for Cygwin and MinGW targets. It diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index 69a23b693b4..2974dcfb20c 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -1756,7 +1756,7 @@ Constant integer 1 A floating point constant 0.0 @item R -Integer constant in the range -6 @dots{} 5. +Integer constant in the range @minus{}6 @dots{} 5. @item Q A memory address based on Y or Z pointer with displacement. @@ -1787,7 +1787,7 @@ Constant that fits in 4 bits Constant that fits in 5 bits @item L -Constant that is one of -1, 4, -4, 7, 8, 12, 16, 20, 32, 48 +Constant that is one of @minus{}1, 4, @minus{}4, 7, 8, 12, 16, 20, 32, 48 @item G Floating point constant that is legal for store immediate @@ -2381,13 +2381,13 @@ RETN, RETI, RETX, RETE, ASTAT, SEQSTAT and USP. Any register except accumulators or CC. @item Ksh -Signed 16 bit integer (in the range -32768 to 32767) +Signed 16 bit integer (in the range @minus{}32768 to 32767) @item Kuh Unsigned 16 bit integer (in the range 0 to 65535) @item Ks7 -Signed 7 bit integer (in the range -64 to 63) +Signed 7 bit integer (in the range @minus{}64 to 63) @item Ku7 Unsigned 7 bit integer (in the range 0 to 127) @@ -2396,10 +2396,10 @@ Unsigned 7 bit integer (in the range 0 to 127) Unsigned 5 bit integer (in the range 0 to 31) @item Ks4 -Signed 4 bit integer (in the range -8 to 7) +Signed 4 bit integer (in the range @minus{}8 to 7) @item Ks3 -Signed 3 bit integer (in the range -3 to 4) +Signed 3 bit integer (in the range @minus{}3 to 4) @item Ku3 Unsigned 3 bit integer (in the range 0 to 7) @@ -2511,28 +2511,28 @@ Matches multiple registers in a PARALLEL to form a larger register. Used to match function return values. @item Is3 --8 @dots{} 7 +@minus{}8 @dots{} 7 @item IS1 --128 @dots{} 127 +@minus{}128 @dots{} 127 @item IS2 --32768 @dots{} 32767 +@minus{}32768 @dots{} 32767 @item IU2 0 @dots{} 65535 @item In4 --8 @dots{} -1 or 1 @dots{} 8 +@minus{}8 @dots{} @minus{}1 or 1 @dots{} 8 @item In5 --16 @dots{} -1 or 1 @dots{} 16 +@minus{}16 @dots{} @minus{}1 or 1 @dots{} 16 @item In6 --32 @dots{} -1 or 1 @dots{} 32 +@minus{}32 @dots{} @minus{}1 or 1 @dots{} 32 @item IM2 --65536 @dots{} -1 +@minus{}65536 @dots{} @minus{}1 @item Ilb An 8 bit value with exactly one bit set. @@ -2717,7 +2717,7 @@ A constant that cannot be loaded using @code{lui}, @code{addiu} or @code{ori}. @item N -A constant in the range -65535 to -1 (inclusive). +A constant in the range @minus{}65535 to @minus{}1 (inclusive). @item O A signed 15-bit constant. @@ -2893,7 +2893,33 @@ A register indirect memory operand A constant in the range of 0 to 255. @item N -A constant in the range of 0 to -255. +A constant in the range of 0 to @minus{}255. + +@end table + +@item RX---@file{config/rx/constraints.md} +@table @code +@item Q +An address which does not involve register indirect addressing or +pre/post increment/decrement addressing. + +@item Symbol +A symbol reference. + +@item Int08 +A constant in the range @minus{}256 to 255, inclusive. + +@item Sint08 +A constant in the range @minus{}128 to 127, inclusive. + +@item Sint16 +A constant in the range @minus{}32768 to 32767, inclusive. + +@item Sint24 +A constant in the range @minus{}8388608 to 8388607, inclusive. + +@item Uint04 +A constant in the range 0 to 15, inclusive. @end table @@ -3012,7 +3038,7 @@ An immediate for and/xor/or instructions. const_int is treated as a 32 bit valu An immediate for the @code{iohl} instruction. const_int is treated as a 32 bit value. @item I -A constant in the range [-64, 63] for shift/rotate instructions. +A constant in the range [@minus{}64, 63] for shift/rotate instructions. @item J An unsigned 7-bit constant for conversion/nop/channel instructions. @@ -3083,7 +3109,7 @@ Value appropriate as displacement. @table @code @item (0..4095) for short displacement -@item (-524288..524287) +@item (@minus{}524288..524287) for long displacement @end table @@ -5011,11 +5037,19 @@ operations in addition to updating the stack pointer. @item @samp{check_stack} If stack checking cannot be done on your system by probing the stack with a load or store instruction (@pxref{Stack Checking}), define this pattern -to perform the needed check and signaling an error if the stack -has overflowed. The single operand is the location in the stack furthest -from the current stack pointer that you need to validate. Normally, -on machines where this pattern is needed, you would obtain the stack -limit from a global or thread-specific variable or register. +to perform the needed check and signal an error if the stack has overflowed. +The single operand is the address in the stack furthest from the current +stack pointer that you need to validate. Normally, on machines where this +pattern is needed, you would obtain the stack limit from a global or +thread-specific variable or register. + +@cindex @code{probe_stack} instruction pattern +@item @samp{probe_stack} +If stack checking can be done on your system by probing the stack but doing +it with a load or store instruction is not optimal (@pxref{Stack Checking}), +define this pattern to do the probing differently and signal an error if +the stack has overflowed. The single operand is the memory location in the +stack that needs to be probed. @cindex @code{nonlocal_goto} instruction pattern @item @samp{nonlocal_goto} diff --git a/gcc/doc/plugins.texi b/gcc/doc/plugins.texi index bb32bccbf18..123f67075ad 100644 --- a/gcc/doc/plugins.texi +++ b/gcc/doc/plugins.texi @@ -136,6 +136,7 @@ enum plugin_event PLUGIN_REGISTER_GGC_CACHES, /* Register an extra GGC cache table. */ PLUGIN_ATTRIBUTES, /* Called during attribute registration */ PLUGIN_START_UNIT, /* Called before processing a translation unit. */ + PLUGIN_PRAGMAS, /* Called during pragma registration. */ PLUGIN_EVENT_LAST /* Dummy event used for indexing callback array. */ @}; @@ -156,6 +157,11 @@ For the PLUGIN_PASS_MANAGER_SETUP, PLUGIN_INFO, PLUGIN_REGISTER_GGC_ROOTS and PLUGIN_REGISTER_GGC_CACHES pseudo-events the @code{callback} should be null, and the @code{user_data} is specific. +When the PLUGIN_PRAGMAS event is triggered (with a null +pointer as data from GCC), plugins may register their own pragmas +using functions like @code{c_register_pragma} or +@code{c_register_pragma_with_expansion}. + @section Interacting with the pass manager There needs to be a way to add/reorder/remove passes dynamically. This @@ -165,7 +171,7 @@ such as CFG or an IPA pass) and optimization plugins. Basic support for inserting new passes or replacing existing passes is provided. A plugin registers a new pass with GCC by calling @code{register_callback} with the @code{PLUGIN_PASS_MANAGER_SETUP} -event and a pointer to a @code{struct plugin_pass} object defined as follows +event and a pointer to a @code{struct register_pass_info} object defined as follows @smallexample enum pass_positioning_ops @@ -175,7 +181,7 @@ enum pass_positioning_ops PASS_POS_REPLACE // Replace the reference pass. @}; -struct plugin_pass +struct register_pass_info @{ struct opt_pass *pass; /* New pass provided by the plugin. */ const char *reference_pass_name; /* Name of the reference pass for hooking @@ -192,7 +198,7 @@ int plugin_init (struct plugin_name_args *plugin_info, struct plugin_gcc_version *version) @{ - struct plugin_pass pass_info; + struct register_pass_info pass_info; ... diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi index ba72b48096b..4888eb3f1e1 100644 --- a/gcc/doc/rtl.texi +++ b/gcc/doc/rtl.texi @@ -420,6 +420,11 @@ the size is implied by the mode. @findex MEM_ALIGN @item MEM_ALIGN (@var{x}) The known alignment in bits of the memory reference. + +@findex MEM_ADDR_SPACE +@item MEM_ADDR_SPACE (@var{x}) +The address space of the memory reference. This will commonly be zero +for the generic address space. @end table @item REG @@ -2364,9 +2369,14 @@ Similar but represent left and right rotate. If @var{c} is a constant, use @code{rotate}. @findex abs +@findex ss_abs @cindex absolute value @item (abs:@var{m} @var{x}) +@item (ss_abs:@var{m} @var{x}) Represents the absolute value of @var{x}, computed in mode @var{m}. +@code{ss_abs} ensures that an out-of-bounds result saturates to the +maximum signed value. + @findex sqrt @cindex square root diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi index 22b27e76ec9..4cbc36f14a3 100644 --- a/gcc/doc/sourcebuild.texi +++ b/gcc/doc/sourcebuild.texi @@ -93,12 +93,16 @@ The Objective-C and Objective-C++ runtime library. @item libstdc++-v3 The C++ runtime library. +@item lto-plugin +Plugin used by @command{gold} if link-time optimizations are enabled. + @item maintainer-scripts Scripts used by the @code{gccadmin} account on @code{gcc.gnu.org}. @item zlib -The @code{zlib} compression library, used by the Java front end and as -part of the Java runtime library. +The @code{zlib} compression library, used by the Java front end, as +part of the Java runtime library, and for compressing and uncompressing +GCC's intermediate language in LTO object files. @end table The build system in the top level directory, including how recursion @@ -137,11 +141,12 @@ The @file{gcc} directory contains the following subdirectories: @item @var{language} Subdirectories for various languages. Directories containing a file @file{config-lang.in} are language subdirectories. The contents of -the subdirectories @file{cp} (for C++), @file{objc} (for Objective-C) -and @file{objcp} (for Objective-C++) are documented in this manual -(@pxref{Passes, , Passes and Files of the Compiler}); those for other -languages are not. @xref{Front End, , Anatomy of a Language Front End}, -for details of the files in these directories. +the subdirectories @file{cp} (for C++), @file{lto} (for LTO), +@file{objc} (for Objective-C) and @file{objcp} (for Objective-C++) are +documented in this manual (@pxref{Passes, , Passes and Files of the +Compiler}); those for other languages are not. @xref{Front End, , +Anatomy of a Language Front End}, for details of the files in these +directories. @item config Configuration files for supported architectures and operating @@ -821,6 +826,7 @@ here; FIXME: document the others. * Ada Tests:: The Ada language testsuites. * C Tests:: The C language testsuites. * libgcj Tests:: The Java library testsuites. +* LTO Testing:: Support for testing link-time optimizations. * gcov Testing:: Support for testing gcov. * profopt Testing:: Support for testing profile-directed optimizations. * compat Testing:: Support for testing binary compatibility. @@ -1347,6 +1353,42 @@ bugs in libgcj that had caused Mauve test failures. We encourage developers to contribute test cases to Mauve. +@node LTO Testing +@subsection Support for testing link-time optimizations + +Tests for link-time optimizations usually require multiple source files +that are compiled separately, perhaps with different sets of options. +There are several special-purpose test directives used for these tests. + +@table @code +@item @{ dg-lto-do @var{do-what-keyword} @} +@var{do-what-keyword} specifies how the test is compiled and whether +it is executed. It is one of: + +@table @code +@item assemble +Compile with @option{-c} to produce a relocatable object file. +@item link +Compile, assemble, and link to produce an executable file. +@item run +Produce and run an executable file, which is expected to return +an exit code of 0. +@end table + +The default is @code{assemble}. That can be overridden for a set of +tests by redefining @code{dg-do-what-default} within the @code{.exp} +file for those tests. + +Unlike @code{dg-do}, @code{dg-lto-do} does not support an optional +@samp{target} or @samp{xfail} list. Use @code{dg-skip-if}, +@code{dg-xfail-if}, or @code{dg-xfail-run-if}. + +@item @{ dg-lto-options @{ @{ @var{options} @} [@{ @var{options} @}] @} [@{ target @var{selector} @}]@} +This directive provides a list of one or more sets of compiler options +to override @var{LTO_OPTIONS}. Each test will be compiled and run with +each of these sets of options. +@end table + @node gcov Testing @subsection Support for testing @command{gcov} diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 27263d91c59..c69ef0c73ab 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -55,6 +55,7 @@ through the macros defined in the @file{.h} file. * MIPS Coprocessors:: MIPS coprocessor support and how to customize it. * PCH Target:: Validity checking for precompiled headers. * C++ ABI:: Controlling C++ ABI changes. +* Named Address Spaces:: Adding support for named address spaces * Misc:: Everything else. @end menu @@ -813,8 +814,22 @@ parsed. Don't use this macro to turn on various extra optimizations for @option{-O}. That is what @code{OPTIMIZATION_OPTIONS} is for. + +If you need to do something whenever the optimization level is +changed via the optimize attribute or pragma, see +@code{TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE} @end defmac +@deftypefn {Target Hook} void TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE (void) +This target function is similar to the macro @code{OVERRIDE_OPTIONS} +but is called when the optimize level is changed via an attribute or +pragma or when it is reset at the end of the code affected by the +attribute or pragma. It is not called at the beginning of compilation +when @code{OVERRIDE_OPTIONS} is called so if you want to perform these +actions then, you should have @code{OVERRIDE_OPTIONS} call +@code{TARGET_OVERRIDE_OPTIONS_AFTER_CHANGE}. +@end deftypefn + @defmac C_COMMON_OVERRIDE_OPTIONS This is similar to @code{OVERRIDE_OPTIONS} but is only used in the C language frontends (C, Objective-C, C++, Objective-C++) and so can be @@ -2349,6 +2364,11 @@ with it, as well as defining these macros. Define this if the machine has any stack-like registers. @end defmac +@defmac STACK_REG_COVER_CLASS +This is a cover class containing the stack registers. Define this if +the machine has any stack-like registers. +@end defmac + @defmac FIRST_STACK_REG The number of the first stack-like register. This one is the top of the stack. @@ -3524,7 +3544,7 @@ dynamically if their size exceeds @code{STACK_CHECK_MAX_VAR_SIZE} bytes. @defmac STACK_CHECK_BUILTIN A nonzero value if stack checking is done by the configuration files in a machine-dependent manner. You should define this macro if stack checking -is require by the ABI of your machine or if you would like to do stack +is required by the ABI of your machine or if you would like to do stack checking in some more efficient way than the generic approach. The default value of this macro is zero. @end defmac @@ -3536,11 +3556,12 @@ like to do static stack checking in some more efficient way than the generic approach. The default value of this macro is zero. @end defmac -@defmac STACK_CHECK_PROBE_INTERVAL -An integer representing the interval at which GCC must generate stack -probe instructions. You will normally define this macro to be no larger -than the size of the ``guard pages'' at the end of a stack area. The -default value of 4096 is suitable for most systems. +@defmac STACK_CHECK_PROBE_INTERVAL_EXP +An integer specifying the interval at which GCC must generate stack probe +instructions, defined as 2 raised to this integer. You will normally +define this macro so that the interval be no larger than the size of +the ``guard pages'' at the end of a stack area. The default value +of 12 (4096-byte interval) is suitable for most systems. @end defmac @defmac STACK_CHECK_PROBE_LOAD @@ -3549,6 +3570,15 @@ as a load instruction and zero if GCC should use a store instruction. The default is zero, which is the most efficient choice on most systems. @end defmac +@defmac STACK_CHECK_MOVING_SP +An integer which is nonzero if GCC should move the stack pointer page by page +when doing probes. This can be necessary on systems where the stack pointer +contains the bottom address of the memory area accessible to the executing +thread at any point in time. In this situation an alternate signal stack +is required in order to be able to recover from a stack overflow. The +default value of this macro is zero. +@end defmac + @defmac STACK_CHECK_PROTECT The number of bytes of stack needed to recover from a stack overflow, for languages where such a recovery is supported. The default value of @@ -3783,7 +3813,7 @@ registers @code{regs_ever_live} and @code{call_used_regs}. If @code{ELIMINABLE_REGS} is defined, this macro will be not be used and need not be defined. Otherwise, it must be defined even if -@code{TARGET_FRAME_POINTER_REQUIRED} is always return true; in that +@code{TARGET_FRAME_POINTER_REQUIRED} always returns true; in that case, you may set @var{depth-var} to anything. @end defmac @@ -4200,7 +4230,6 @@ on the stack. The compiler knows how to track the amount of stack space used for arguments without any special help. @end defmac - @defmac FUNCTION_ARG_OFFSET (@var{mode}, @var{type}) If defined, a C expression that is the number of bytes to add to the offset of the argument passed in memory. This is needed for the SPU, @@ -4394,7 +4423,7 @@ compiled. @end defmac @deftypefn {Target Hook} rtx TARGET_LIBCALL_VALUE (enum machine_mode -@var{mode}, rtx @var{fun}) +@var{mode}, const_rtx @var{fun}) Define this hook if the back-end needs to know the name of the libcall function in order to determine where the result should be returned. @@ -5365,9 +5394,10 @@ post-address side-effect generation involving a register displacement. @defmac CONSTANT_ADDRESS_P (@var{x}) A C expression that is 1 if the RTX @var{x} is a constant which -is a valid address. On most machines, this can be defined as -@code{CONSTANT_P (@var{x})}, but a few machines are more restrictive -in which constant addresses are supported. +is a valid address. On most machines the default definition of +@code{(CONSTANT_P (@var{x}) && GET_CODE (@var{x}) != CONST_DOUBLE)} +is acceptable, but a few machines are more restrictive as to which +constant addresses are supported. @end defmac @defmac CONSTANT_P (@var{x}) @@ -5628,7 +5658,7 @@ should comply with the semantics expected by @code{REALIGN_LOAD} described above. If this hook is not defined, then @var{addr} will be used as the argument @var{OFF} to @code{REALIGN_LOAD}, in which case the low -log2(@var{VS})-1 bits of @var{addr} will be considered. +log2(@var{VS}) @minus{} 1 bits of @var{addr} will be considered. @end deftypefn @deftypefn {Target Hook} tree TARGET_VECTORIZE_BUILTIN_MUL_WIDEN_EVEN (tree @var{x}) @@ -6122,7 +6152,7 @@ this macro is defined, it should produce a nonzero value when @code{STRICT_ALIGNMENT} is nonzero. @end defmac -@defmac MOVE_RATIO +@defmac MOVE_RATIO (@var{speed}) The threshold of number of scalar memory-to-memory move insns, @emph{below} which a sequence of insns should be generated instead of a string move insn or a library call. Increasing the value will always @@ -6132,6 +6162,9 @@ Note that on machines where the corresponding move insn is a @code{define_expand} that emits a sequence of insns, this macro counts the number of such sequences. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, a reasonable default is used. @end defmac @@ -6147,12 +6180,15 @@ A C expression used by @code{move_by_pieces} to determine the largest unit a load or store used to copy memory is. Defaults to @code{MOVE_MAX}. @end defmac -@defmac CLEAR_RATIO +@defmac CLEAR_RATIO (@var{speed}) The threshold of number of scalar move insns, @emph{below} which a sequence of insns should be generated to clear memory instead of a string clear insn or a library call. Increasing the value will always make code faster, but eventually incurs high cost in increased code size. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, a reasonable default is used. @end defmac @@ -6163,13 +6199,16 @@ will be used. Defaults to 1 if @code{move_by_pieces_ninsns} returns less than @code{CLEAR_RATIO}. @end defmac -@defmac SET_RATIO +@defmac SET_RATIO (@var{speed}) The threshold of number of scalar move insns, @emph{below} which a sequence of insns should be generated to set memory to a constant value, instead of a block set insn or a library call. Increasing the value will always make code faster, but eventually incurs high cost in increased code size. +The parameter @var{speed} is true if the code is currently being +optimized for speed rather than size. + If you don't define this, it defaults to the value of @code{MOVE_RATIO}. @end defmac @@ -6184,7 +6223,7 @@ than @code{SET_RATIO}. @defmac STORE_BY_PIECES_P (@var{size}, @var{alignment}) A C expression used to determine whether @code{store_by_pieces} will be -used to set a chunk of memory to a constant string value, or whether some +used to set a chunk of memory to a constant string value, or whether some other mechanism will be used. Used by @code{__builtin_strcpy} when called with a constant source string. Defaults to 1 if @code{move_by_pieces_ninsns} returns less @@ -6250,7 +6289,7 @@ Define this macro if a non-short-circuit operation produced by @code{BRANCH_COST} is greater than or equal to the value 2. @end defmac -@deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, int @var{code}, int @var{outer_code}, int *@var{total}) +@deftypefn {Target Hook} bool TARGET_RTX_COSTS (rtx @var{x}, int @var{code}, int @var{outer_code}, int *@var{total}, bool @var{speed}) This target hook describes the relative costs of RTL expressions. The cost may depend on the precise form of the expression, which is @@ -6269,15 +6308,15 @@ necessary. Traditionally, the default costs are @code{COSTS_N_INSNS (5)} for multiplications, @code{COSTS_N_INSNS (7)} for division and modulus operations, and @code{COSTS_N_INSNS (1)} for all other operations. -When optimizing for code size, i.e.@: when @code{optimize_size} is -nonzero, this target hook should be used to estimate the relative +When optimizing for code size, i.e.@: when @code{speed} is +false, this target hook should be used to estimate the relative size cost of an expression, again relative to @code{COSTS_N_INSNS}. The hook returns true when all subexpressions of @var{x} have been processed, and false when @code{rtx_cost} should recurse. @end deftypefn -@deftypefn {Target Hook} int TARGET_ADDRESS_COST (rtx @var{address}) +@deftypefn {Target Hook} int TARGET_ADDRESS_COST (rtx @var{address}, bool @var{speed}) This hook computes the cost of an addressing mode that contains @var{address}. If not defined, the cost is computed from the @var{address} expression and the @code{TARGET_RTX_COST} hook. @@ -6379,7 +6418,7 @@ debug output to. @var{verbose} is the verbose level provided by list of instructions that are ready to be scheduled. @var{n_readyp} is a pointer to the number of elements in the ready list. The scheduler reads the ready list in reverse order, starting with -@var{ready}[@var{*n_readyp}-1] and going to @var{ready}[0]. @var{clock} +@var{ready}[@var{*n_readyp} @minus{} 1] and going to @var{ready}[0]. @var{clock} is the timer tick of the scheduler. You may modify the ready list and the number of ready insns. The return value is the number of insns that can issue this cycle; normally this is just @code{issue_rate}. See also @@ -6610,7 +6649,7 @@ speculative dependencies and therefore can be scheduled speculatively. The hook is used to check if the pattern of @var{insn} has a speculative version and, in case of successful check, to generate that speculative pattern. The hook should return 1, if the instruction has a speculative form, -or -1, if it doesn't. @var{request} describes the type of requested +or @minus{}1, if it doesn't. @var{request} describes the type of requested speculation. If the return value equals 1 then @var{new_pat} is assigned the generated speculative pattern. @end deftypefn @@ -9511,7 +9550,7 @@ attributes, or a copy of the list may be made if further changes are needed. @end deftypefn -@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (tree @var{fndecl}) +@deftypefn {Target Hook} bool TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P (const_tree @var{fndecl}) @cindex inlining This target hook returns @code{true} if it is ok to inline @var{fndecl} into the current function, despite its having target-specific @@ -9811,6 +9850,105 @@ defined. Use this hook to make adjustments to the class (eg, tweak visibility or perform any other required target modifications). @end deftypefn +@node Named Address Spaces +@section Adding support for named address spaces +@cindex named address spaces + +The draft technical report of the ISO/IEC JTC1 S22 WG14 N1275 +standards committee, @cite{Programming Languages - C - Extensions to +support embedded processors}, specifies a syntax for embedded +processors to specify alternate address spaces. You can configure a +GCC port to support section 5.1 of the draft report to add support for +address spaces other than the default address space. These address +spaces are new keywords that are similar to the @code{volatile} and +@code{const} type attributes. + +Pointers to named address spaces can a a different size than +pointers to the generic address space. + +For example, the SPU port uses the @code{__ea} address space to refer +to memory in the host processor, rather than memory local to the SPU +processor. Access to memory in the @code{__ea} address space involves +issuing DMA operations to move data between the host processor and the +local processor memory address space. Pointers in the @code{__ea} +address space are either 32 bits or 64 bits based on the +@option{-mea32} or @option{-mea64} switches (native SPU pointers are +always 32 bits). + +Internally, address spaces are represented as a small integer in the +range 0 to 15 with address space 0 being reserved for the generic +address space. + +@defmac TARGET_ADDR_SPACE_KEYWORDS +A list of @code{ADDR_SPACE_KEYWORD} macros to define each named +address keyword. The @code{ADDR_SPACE_KEYWORD} macro takes two +arguments, the keyword string and the number of the named address +space. For example, the SPU port uses the following to declare +@code{__ea} as the keyword for named address space #1: +@smallexample +#define ADDR_SPACE_EA 1 +#define TARGET_ADDR_SPACE_KEYWORDS ADDR_SPACE_KEYWORD ("__ea", ADDR_SPACE_EA) +@end smallexample +@end defmac + +@deftypefn {Target Hook} {enum machine_mode} TARGET_ADDR_SPACE_POINTER_MODE (addr_space_t @var{address_space}) +Define this to return the machine mode to use for pointers to +@var{address_space} if the target supports named address spaces. +The default version of this hook returns @code{ptr_mode} for the +generic address space only. +@end deftypefn + +@deftypefn {Target Hook} {enum machine_mode} TARGET_ADDR_SPACE_ADDRESS_MODE (addr_space_t @var{address_space}) +Define this to return the machine mode to use for addresses in +@var{address_space} if the target supports named address spaces. +The default version of this hook returns @code{Pmode} for the +generic address space only. +@end deftypefn + +@deftypefn {Target Hook} bool TARGET_ADDR_SPACE_VALID_POINTER_MODE (enum machine_mode @var{mode}, addr_space_t @var{as}) +Define this to return nonzero if the port can handle pointers +with machine mode @var{mode} to address space @var{as}. This target +hook is the same as the @code{TARGET_VALID_POINTER_MODE} target hook, +except that it includes explicit named address space support. The default +version of this hook returns true for the modes returned by either the +@code{TARGET_ADDR_SPACE_POINTER_MODE} or @code{TARGET_ADDR_SPACE_ADDRESS_MODE} +target hooks for the given address space. +@end deftypefn + +@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P (enum machine_mode @var{mode}, rtx @var{exp}, bool @var{strict}, addr_space_t @var{as}) +Define this to return true if @var{exp} is a valid address for mode +@var{mode} in the named address space @var{as}. The @var{strict} +parameter says whether strict addressing is in effect after reload has +finished. This target hook is the same as the +@code{TARGET_LEGITIMATE_ADDRESS_P} target hook, except that it includes +explicit named address space support. +@end deftypefn + +@deftypefn {Target Hook} {rtx} TARGET_ADDR_SPACE_LEGITIMIZE_ADDRESS (rtx @var{x}, rtx @var{oldx}, enum machine_mode @var{mode}, addr_space_t @var{as}) +Define this to modify an invalid address @var{x} to be a valid address +with mode @var{mode} in the named address space @var{as}. This target +hook is the same as the @code{TARGET_LEGITIMIZE_ADDRESS} target hook, +except that it includes explicit named address space support. +@end deftypefn + +@deftypefn {Target Hook} {bool} TARGET_ADDR_SPACE_SUBSET_P (addr_space_t @var{superset}, addr_space_t @var{subset}) +Define this to return whether the @var{subset} named address space is +contained within the @var{superset} named address space. Pointers to +a named address space that is a subset of another named address space +will be converted automatically without a cast if used together in +arithmetic operations. Pointers to a superset address space can be +converted to pointers to a subset address space via explict casts. +@end deftypefn + +@deftypefn {Target Hook} {rtx} TARGET_ADDR_SPACE_CONVERT (rtx @var{op}, tree @var{from_type}, tree @var{to_type}) +Define this to convert the pointer expression represented by the RTL +@var{op} with type @var{from_type} that points to a named address +space to a new pointer expression with type @var{to_type} that points +to a different named address space. When this hook it called, it is +guaranteed that one of the two address spaces is a subset of the other, +as determined by the @code{TARGET_ADDR_SPACE_SUBSET_P} target hook. +@end deftypefn + @node Misc @section Miscellaneous Parameters @cindex parameters, miscellaneous @@ -10532,6 +10670,16 @@ only language front ends that use those two functions will call @samp{TARGET_INIT_BUILTINS}. @end deftypefn +@deftypefn {Target Hook} tree TARGET_BUILTIN_FUNCTION (unsigned @var{code}, bool @var{initialize_p}) +Define this hook if you have any machine-specific built-in functions +that need to be defined. It should be a function that returns the +builtin function declaration for the builtin function code @var{code}. +If there is no such builtin and it cannot be initialized at this time +if @var{initialize_p} is true the function should return @code{NULL_TREE}. +If @var{code} is out of range the function should return +@code{error_mark_node}. +@end deftypefn + @deftypefn {Target Hook} rtx TARGET_EXPAND_BUILTIN (tree @var{exp}, rtx @var{target}, rtx @var{subtarget}, enum machine_mode @var{mode}, int @var{ignore}) Expand a call to a machine specific built-in function that was set up by @@ -10718,6 +10866,12 @@ to have to make special provisions in @code{INITIAL_ELIMINATION_OFFSET} to reserve space for caller-saved target registers. @end deftypefn +@deftypefn {Target Hook} bool TARGET_HAVE_CONDITIONAL_EXECUTION (void) +This target hook returns true if the target supports conditional execution. +This target hook is required only when the target has several different +modes and they have different conditional execution capability, such as ARM. +@end deftypefn + @defmac POWI_MAX_MULTS If defined, this macro is interpreted as a signed integer C expression that specifies the maximum number of floating point multiplications @@ -10895,7 +11049,6 @@ to the stack. Therefore, this hook should return true in general, but false for naked functions. The default implementation always returns true. @end deftypefn - @deftypevr {Target Hook} {unsigned HOST_WIDE_INT} TARGET_CONST_ANCHOR On some architectures it can take multiple instructions to synthesize a constant. If there is another constant already in a register that diff --git a/gcc/dse.c b/gcc/dse.c index 9d3e2c07ed6..a883bcd3d69 100644 --- a/gcc/dse.c +++ b/gcc/dse.c @@ -826,9 +826,9 @@ replace_inc_dec (rtx *r, void *d) case POST_INC: { rtx r1 = XEXP (x, 0); - rtx c = gen_int_mode (data->size, Pmode); - emit_insn_before (gen_rtx_SET (Pmode, r1, - gen_rtx_PLUS (Pmode, r1, c)), + rtx c = gen_int_mode (data->size, GET_MODE (r1)); + emit_insn_before (gen_rtx_SET (VOIDmode, r1, + gen_rtx_PLUS (GET_MODE (r1), r1, c)), data->insn); return -1; } @@ -837,9 +837,9 @@ replace_inc_dec (rtx *r, void *d) case POST_DEC: { rtx r1 = XEXP (x, 0); - rtx c = gen_int_mode (-data->size, Pmode); - emit_insn_before (gen_rtx_SET (Pmode, r1, - gen_rtx_PLUS (Pmode, r1, c)), + rtx c = gen_int_mode (-data->size, GET_MODE (r1)); + emit_insn_before (gen_rtx_SET (VOIDmode, r1, + gen_rtx_PLUS (GET_MODE (r1), r1, c)), data->insn); return -1; } @@ -851,7 +851,7 @@ replace_inc_dec (rtx *r, void *d) insn that contained it. */ rtx add = XEXP (x, 0); rtx r1 = XEXP (add, 0); - emit_insn_before (gen_rtx_SET (Pmode, r1, add), data->insn); + emit_insn_before (gen_rtx_SET (VOIDmode, r1, add), data->insn); return -1; } @@ -1068,6 +1068,8 @@ canon_address (rtx mem, HOST_WIDE_INT *offset, cselib_val **base) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (mem)); rtx mem_address = XEXP (mem, 0); rtx expanded_address, address; int expanded; @@ -1107,7 +1109,7 @@ canon_address (rtx mem, *alias_set_out = 0; - cselib_lookup (mem_address, Pmode, 1); + cselib_lookup (mem_address, address_mode, 1); if (dump_file) { @@ -1173,7 +1175,8 @@ canon_address (rtx mem, address = XEXP (address, 0); } - if (const_or_frame_p (address)) + if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (mem)) + && const_or_frame_p (address)) { group_info_t group = get_group_info (address); @@ -1186,7 +1189,7 @@ canon_address (rtx mem, } } - *base = cselib_lookup (address, Pmode, true); + *base = cselib_lookup (address, address_mode, true); *group_id = -1; if (*base == NULL) diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 26e85940c23..e5648090f9c 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -224,6 +224,8 @@ static GTY(()) section *debug_line_section; static GTY(()) section *debug_loc_section; static GTY(()) section *debug_pubnames_section; static GTY(()) section *debug_pubtypes_section; +static GTY(()) section *debug_dcall_section; +static GTY(()) section *debug_vcall_section; static GTY(()) section *debug_str_section; static GTY(()) section *debug_ranges_section; static GTY(()) section *debug_frame_section; @@ -5399,6 +5401,7 @@ static int output_indirect_string (void **, void *); static void dwarf2out_init (const char *); static void dwarf2out_finish (const char *); +static void dwarf2out_assembly_start (void); static void dwarf2out_define (unsigned int, const char *); static void dwarf2out_undef (unsigned int, const char *); static void dwarf2out_start_source_file (unsigned, const char *); @@ -5413,6 +5416,10 @@ static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree, dw_die_ref); static void dwarf2out_abstract_function (tree); static void dwarf2out_var_location (rtx); +static void dwarf2out_direct_call (tree); +static void dwarf2out_virtual_call_token (tree, int); +static void dwarf2out_copy_call_info (rtx, rtx); +static void dwarf2out_virtual_call (int); static void dwarf2out_begin_function (tree); static void dwarf2out_set_name (tree, tree); @@ -5422,6 +5429,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { dwarf2out_init, dwarf2out_finish, + dwarf2out_assembly_start, dwarf2out_define, dwarf2out_undef, dwarf2out_start_source_file, @@ -5448,6 +5456,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = debug_nothing_int, /* handle_pch */ dwarf2out_var_location, dwarf2out_switch_text_section, + dwarf2out_direct_call, + dwarf2out_virtual_call_token, + dwarf2out_copy_call_info, + dwarf2out_virtual_call, dwarf2out_set_name, 1 /* start_end_main_source_file */ }; @@ -5828,6 +5840,45 @@ static GTY(()) bool have_location_lists; /* Unique label counter. */ static GTY(()) unsigned int loclabel_num; +/* Unique label counter for point-of-call tables. */ +static GTY(()) unsigned int poc_label_num; + +/* The direct call table structure. */ + +typedef struct GTY(()) dcall_struct { + unsigned int poc_label_num; + tree poc_decl; + dw_die_ref targ_die; +} +dcall_entry; + +DEF_VEC_O(dcall_entry); +DEF_VEC_ALLOC_O(dcall_entry, gc); + +/* The virtual call table structure. */ + +typedef struct GTY(()) vcall_struct { + unsigned int poc_label_num; + unsigned int vtable_slot; +} +vcall_entry; + +DEF_VEC_O(vcall_entry); +DEF_VEC_ALLOC_O(vcall_entry, gc); + +/* Pointers to the direct and virtual call tables. */ +static GTY (()) VEC (dcall_entry, gc) * dcall_table = NULL; +static GTY (()) VEC (vcall_entry, gc) * vcall_table = NULL; + +/* A hash table to map INSN_UIDs to vtable slot indexes. */ + +struct GTY (()) vcall_insn { + int insn_uid; + unsigned int vtable_slot; +}; + +static GTY ((param_is (struct vcall_insn))) htab_t vcall_insn_table; + #ifdef DWARF2_DEBUGGING_INFO /* Record whether the function being analyzed contains inlined functions. */ static int current_function_has_inlines; @@ -6165,6 +6216,12 @@ static void gen_remaining_tmpl_value_param_die_attribute (void); #ifndef DEBUG_PUBTYPES_SECTION #define DEBUG_PUBTYPES_SECTION ".debug_pubtypes" #endif +#ifndef DEBUG_DCALL_SECTION +#define DEBUG_DCALL_SECTION ".debug_dcall" +#endif +#ifndef DEBUG_VCALL_SECTION +#define DEBUG_VCALL_SECTION ".debug_vcall" +#endif #ifndef DEBUG_STR_SECTION #define DEBUG_STR_SECTION ".debug_str" #endif @@ -6425,6 +6482,10 @@ dwarf_tag_name (unsigned int tag) return "DW_TAG_shared_type"; case DW_TAG_type_unit: return "DW_TAG_type_unit"; + case DW_TAG_rvalue_reference_type: + return "DW_TAG_rvalue_reference_type"; + case DW_TAG_template_alias: + return "DW_TAG_template_alias"; case DW_TAG_GNU_template_parameter_pack: return "DW_TAG_GNU_template_parameter_pack"; case DW_TAG_GNU_formal_parameter_pack: @@ -6609,6 +6670,16 @@ dwarf_attr_name (unsigned int attr) case DW_AT_signature: return "DW_AT_signature"; + case DW_AT_main_subprogram: + return "DW_AT_main_subprogram"; + case DW_AT_data_bit_offset: + return "DW_AT_data_bit_offset"; + case DW_AT_const_expr: + return "DW_AT_const_expr"; + case DW_AT_enum_class: + return "DW_AT_enum_class"; + case DW_AT_linkage_name: + return "DW_AT_linkage_name"; case DW_AT_MIPS_fde: return "DW_AT_MIPS_fde"; @@ -6647,6 +6718,22 @@ dwarf_attr_name (unsigned int attr) return "DW_AT_body_end"; case DW_AT_GNU_vector: return "DW_AT_GNU_vector"; + case DW_AT_GNU_guarded_by: + return "DW_AT_GNU_guarded_by"; + case DW_AT_GNU_pt_guarded_by: + return "DW_AT_GNU_pt_guarded_by"; + case DW_AT_GNU_guarded: + return "DW_AT_GNU_guarded"; + case DW_AT_GNU_pt_guarded: + return "DW_AT_GNU_pt_guarded"; + case DW_AT_GNU_locks_excluded: + return "DW_AT_GNU_locks_excluded"; + case DW_AT_GNU_exclusive_locks_required: + return "DW_AT_GNU_exclusive_locks_required"; + case DW_AT_GNU_shared_locks_required: + return "DW_AT_GNU_shared_locks_required"; + case DW_AT_GNU_odr_signature: + return "DW_AT_GNU_odr_signature"; case DW_AT_GNU_template_name: return "DW_AT_GNU_template_name"; @@ -6707,6 +6794,14 @@ dwarf_form_name (unsigned int form) return "DW_FORM_ref_udata"; case DW_FORM_indirect: return "DW_FORM_indirect"; + case DW_FORM_sec_offset: + return "DW_FORM_sec_offset"; + case DW_FORM_exprloc: + return "DW_FORM_exprloc"; + case DW_FORM_flag_present: + return "DW_FORM_flag_present"; + case DW_FORM_ref_sig8: + return "DW_FORM_ref_sig8"; default: return "DW_FORM_"; } @@ -10299,7 +10394,7 @@ output_signature (const char *sig, const char *name) int i; for (i = 0; i < DWARF_TYPE_SIGNATURE_SIZE; i++) - dw2_asm_output_data (1, sig[i], "%s", name); + dw2_asm_output_data (1, sig[i], i == 0 ? "%s" : NULL, name); } /* Output the DIE and its attributes. Called recursively to generate @@ -10520,7 +10615,7 @@ output_die (dw_die_ref die) for (i = 0; i < 8; i++) dw2_asm_output_data (1, a->dw_attr_val.v.val_data8[i], - "%s", name); + i == 0 ? "%s" : NULL, name); break; } @@ -10688,7 +10783,11 @@ static void add_pubname (tree decl, dw_die_ref die) { if (TREE_PUBLIC (decl)) - add_pubname_string (dwarf2_name (decl, 1), die); + { + const char *name = dwarf2_name (decl, 1); + if (name) + add_pubname_string (name, die); + } } /* Add a new entry to .debug_pubtypes if appropriate. */ @@ -10718,7 +10817,11 @@ add_pubtype (tree decl, dw_die_ref die) } } else - e.name = xstrdup (dwarf2_name (decl, 1)); + { + e.name = dwarf2_name (decl, 1); + if (e.name) + e.name = xstrdup (e.name); + } /* If we don't have a name for the type, there's no point in adding it to the table. */ @@ -11684,6 +11787,129 @@ output_line_info (void) /* Output the marker for the end of the line number info. */ ASM_OUTPUT_LABEL (asm_out_file, l2); } + +/* Return the size of the .debug_dcall table for the compilation unit. */ + +static unsigned long +size_of_dcall_table (void) +{ + unsigned long size; + unsigned int i; + dcall_entry *p; + tree last_poc_decl = NULL; + + /* Header: version + debug info section pointer + pointer size. */ + size = 2 + DWARF_OFFSET_SIZE + 1; + + /* Each entry: code label + DIE offset. */ + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++) + { + gcc_assert (p->targ_die != NULL); + /* Insert a "from" entry when the point-of-call DIE offset changes. */ + if (p->poc_decl != last_poc_decl) + { + dw_die_ref poc_die = lookup_decl_die (p->poc_decl); + gcc_assert (poc_die); + last_poc_decl = p->poc_decl; + if (poc_die) + size += (DWARF_OFFSET_SIZE + + size_of_uleb128 (poc_die->die_offset)); + } + size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->targ_die->die_offset); + } + + return size; +} + +/* Output the direct call table used to disambiguate PC values when + identical function have been merged. */ + +static void +output_dcall_table (void) +{ + unsigned i; + unsigned long dcall_length = size_of_dcall_table (); + dcall_entry *p; + char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; + tree last_poc_decl = NULL; + + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, dcall_length, + "Length of Direct Call Table"); + dw2_asm_output_data (2, 4, "Version number"); + dw2_asm_output_offset (DWARF_OFFSET_SIZE, debug_info_section_label, + debug_info_section, + "Offset of Compilation Unit Info"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, p); i++) + { + /* Insert a "from" entry when the point-of-call DIE offset changes. */ + if (p->poc_decl != last_poc_decl) + { + dw_die_ref poc_die = lookup_decl_die (p->poc_decl); + last_poc_decl = p->poc_decl; + if (poc_die) + { + dw2_asm_output_data (DWARF_OFFSET_SIZE, 0, "New caller"); + dw2_asm_output_data_uleb128 (poc_die->die_offset, + "Caller DIE offset"); + } + } + ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); + dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); + dw2_asm_output_data_uleb128 (p->targ_die->die_offset, + "Callee DIE offset"); + } +} + +/* Return the size of the .debug_vcall table for the compilation unit. */ + +static unsigned long +size_of_vcall_table (void) +{ + unsigned long size; + unsigned int i; + vcall_entry *p; + + /* Header: version + pointer size. */ + size = 2 + 1; + + /* Each entry: code label + vtable slot index. */ + for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++) + size += DWARF_OFFSET_SIZE + size_of_uleb128 (p->vtable_slot); + + return size; +} + +/* Output the virtual call table used to disambiguate PC values when + identical function have been merged. */ + +static void +output_vcall_table (void) +{ + unsigned i; + unsigned long vcall_length = size_of_vcall_table (); + vcall_entry *p; + char poc_label[MAX_ARTIFICIAL_LABEL_BYTES]; + + if (DWARF_INITIAL_LENGTH_SIZE - DWARF_OFFSET_SIZE == 4) + dw2_asm_output_data (4, 0xffffffff, + "Initial length escape value indicating 64-bit DWARF extension"); + dw2_asm_output_data (DWARF_OFFSET_SIZE, vcall_length, + "Length of Virtual Call Table"); + dw2_asm_output_data (2, 4, "Version number"); + dw2_asm_output_data (1, DWARF2_ADDR_SIZE, "Pointer Size (in bytes)"); + + for (i = 0; VEC_iterate (vcall_entry, vcall_table, i, p); i++) + { + ASM_GENERATE_INTERNAL_LABEL (poc_label, "LPOC", p->poc_label_num); + dw2_asm_output_addr (DWARF_OFFSET_SIZE, poc_label, "Point of call"); + dw2_asm_output_data_uleb128 (p->vtable_slot, "Vtable slot"); + } +} /* Given a pointer to a tree node for some base type, return a pointer to a DIE that describes the given type. @@ -11934,6 +12160,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, add_AT_unsigned (mod_type_die, DW_AT_byte_size, simple_type_size_in_bits (type) / BITS_PER_UNIT); item_type = TREE_TYPE (type); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type))) + add_AT_unsigned (mod_type_die, DW_AT_address_class, + TYPE_ADDR_SPACE (item_type)); } else if (code == REFERENCE_TYPE) { @@ -11941,6 +12170,9 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, add_AT_unsigned (mod_type_die, DW_AT_byte_size, simple_type_size_in_bits (type) / BITS_PER_UNIT); item_type = TREE_TYPE (type); + if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (item_type))) + add_AT_unsigned (mod_type_die, DW_AT_address_class, + TYPE_ADDR_SPACE (item_type)); } else if (code == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE @@ -11971,10 +12203,16 @@ modified_type_die (tree type, int is_const_type, int is_volatile_type, /* Builtin types don't have a DECL_ORIGINAL_TYPE. For those, don't output a DW_TAG_typedef, since there isn't one in the - user's program; just attach a DW_AT_name to the type. */ + user's program; just attach a DW_AT_name to the type. + Don't attach a DW_AT_name to DW_TAG_const_type or DW_TAG_volatile_type + if the base type already has the same name. */ if (name - && (TREE_CODE (name) != TYPE_DECL - || (TREE_TYPE (name) == qualified_type && DECL_NAME (name)))) + && ((TREE_CODE (name) != TYPE_DECL + && (qualified_type == TYPE_MAIN_VARIANT (type) + || (!is_const_type && !is_volatile_type))) + || (TREE_CODE (name) == TYPE_DECL + && TREE_TYPE (name) == qualified_type + && DECL_NAME (name)))) { if (TREE_CODE (name) == TYPE_DECL) /* Could just call add_name_and_src_coords_attributes here, @@ -12137,7 +12375,8 @@ generic_parameter_die (tree parm, tree arg, /* The DW_AT_GNU_template_name attribute of the DIE must be set to the name of the argument. */ name = dwarf2_name (TYPE_P (arg) ? TYPE_NAME (arg) : arg, 1); - add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); + if (name) + add_AT_string (tmpl_die, DW_AT_GNU_template_name, name); } if (TREE_CODE (parm) == PARM_DECL) @@ -12171,13 +12410,10 @@ template_parameter_pack_die (tree parm_pack, dw_die_ref die; int j; - gcc_assert (parent_die - && parm_pack - && DECL_NAME (parm_pack)); + gcc_assert (parent_die && parm_pack); die = new_die (DW_TAG_GNU_template_parameter_pack, parent_die, parm_pack); - add_AT_string (die, DW_AT_name, IDENTIFIER_POINTER (DECL_NAME (parm_pack))); - + add_name_and_src_coords_attributes (die, parm_pack); for (j = 0; j < TREE_VEC_LENGTH (parm_pack_args); j++) generic_parameter_die (parm_pack, TREE_VEC_ELT (parm_pack_args, j), @@ -12677,10 +12913,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case POST_INC: case POST_DEC: case POST_MODIFY: - /* POST_INC and POST_DEC can be handled just like a SUBREG. So we - just fall into the SUBREG code. */ - - /* ... fall through ... */ + return mem_loc_descriptor (XEXP (rtl, 0), mode, initialized); case SUBREG: /* The case of a subreg may arise when we have a local (register) @@ -12688,9 +12921,13 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, up an entire register. For now, just assume that it is legitimate to make the Dwarf info refer to the whole register which contains the given subreg. */ - rtl = XEXP (rtl, 0); + if (!subreg_lowpart_p (rtl)) + break; + rtl = SUBREG_REG (rtl); if (GET_MODE_SIZE (GET_MODE (rtl)) > DWARF2_ADDR_SIZE) break; + if (GET_MODE_CLASS (GET_MODE (rtl)) != MODE_INT) + break; mem_loc_result = mem_loc_descriptor (rtl, mode, initialized); break; @@ -13175,12 +13412,19 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, if (BITS_BIG_ENDIAN) shift = GET_MODE_BITSIZE (GET_MODE (XEXP (rtl, 0))) - shift - size; - add_loc_descr (&mem_loc_result, - int_loc_descriptor (DWARF2_ADDR_SIZE - shift - size)); - add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0)); - add_loc_descr (&mem_loc_result, - int_loc_descriptor (DWARF2_ADDR_SIZE - size)); - add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + if (shift + size != (int) DWARF2_ADDR_SIZE) + { + add_loc_descr (&mem_loc_result, + int_loc_descriptor (DWARF2_ADDR_SIZE + - shift - size)); + add_loc_descr (&mem_loc_result, new_loc_descr (DW_OP_shl, 0, 0)); + } + if (size != (int) DWARF2_ADDR_SIZE) + { + add_loc_descr (&mem_loc_result, + int_loc_descriptor (DWARF2_ADDR_SIZE - size)); + add_loc_descr (&mem_loc_result, new_loc_descr (op, 0, 0)); + } } break; @@ -13202,6 +13446,7 @@ mem_loc_descriptor (rtx rtl, enum machine_mode mode, case ORDERED: case UNEQ: case UNGE: + case UNGT: case UNLE: case UNLT: case LTGT: @@ -13596,71 +13841,101 @@ decl_by_reference_p (tree decl) && DECL_BY_REFERENCE (decl)); } +/* Return single element location list containing loc descr REF. */ -/* Dereference a location expression LOC if DECL is passed by invisible - reference. */ - -static dw_loc_descr_ref -loc_by_reference (dw_loc_descr_ref loc, tree decl) +static dw_loc_list_ref +single_element_loc_list (dw_loc_descr_ref ref) { - HOST_WIDE_INT size; - enum dwarf_location_atom op; + return new_loc_list (ref, NULL, NULL, NULL, 0); +} - if (loc == NULL) - return NULL; +/* Helper function for dw_loc_list. Compute proper Dwarf location descriptor + for VARLOC. */ - if (!decl_by_reference_p (decl)) - return loc; +static dw_loc_descr_ref +dw_loc_list_1 (tree loc, rtx varloc, int want_address, + enum var_init_status initialized) +{ + int have_address = 0; + dw_loc_descr_ref descr; + enum machine_mode mode; - /* If loc is DW_OP_reg{0...31,x}, don't add DW_OP_deref, instead - change it into corresponding DW_OP_breg{0...31,x} 0. Then the - location expression is considered to be address of a memory location, - rather than the register itself. */ - if (((loc->dw_loc_opc >= DW_OP_reg0 && loc->dw_loc_opc <= DW_OP_reg31) - || loc->dw_loc_opc == DW_OP_regx) - && (loc->dw_loc_next == NULL - || (loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_uninit - && loc->dw_loc_next->dw_loc_next == NULL))) + if (want_address != 2) { - if (loc->dw_loc_opc == DW_OP_regx) + gcc_assert (GET_CODE (varloc) == VAR_LOCATION); + /* Single part. */ + if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) { - loc->dw_loc_opc = DW_OP_bregx; - loc->dw_loc_oprnd2.v.val_int = 0; + varloc = XEXP (XEXP (varloc, 1), 0); + mode = GET_MODE (varloc); + if (MEM_P (varloc)) + { + varloc = XEXP (varloc, 0); + have_address = 1; + } + descr = mem_loc_descriptor (varloc, mode, initialized); } else + return 0; + } + else + { + descr = loc_descriptor (varloc, DECL_MODE (loc), initialized); + have_address = 1; + } + + if (!descr) + return 0; + + if (want_address == 2 && !have_address + && (dwarf_version >= 4 || !dwarf_strict)) + { + if (int_size_in_bytes (TREE_TYPE (loc)) > DWARF2_ADDR_SIZE) { - loc->dw_loc_opc - = (enum dwarf_location_atom) - (loc->dw_loc_opc + (DW_OP_breg0 - DW_OP_reg0)); - loc->dw_loc_oprnd1.v.val_int = 0; + expansion_failed (loc, NULL_RTX, + "DWARF address size mismatch"); + return 0; } - return loc; + add_loc_descr (&descr, new_loc_descr (DW_OP_stack_value, 0, 0)); + have_address = 1; + } + /* Show if we can't fill the request for an address. */ + if (want_address && !have_address) + { + expansion_failed (loc, NULL_RTX, + "Want address and only have value"); + return 0; } - size = int_size_in_bytes (TREE_TYPE (decl)); - if (size > DWARF2_ADDR_SIZE || size == -1) - return 0; - else if (size == DWARF2_ADDR_SIZE) - op = DW_OP_deref; - else - op = DW_OP_deref_size; - add_loc_descr (&loc, new_loc_descr (op, size, 0)); - return loc; -} + /* If we've got an address and don't want one, dereference. */ + if (!want_address && have_address) + { + HOST_WIDE_INT size = int_size_in_bytes (TREE_TYPE (loc)); + enum dwarf_location_atom op; -/* Return single element location list containing loc descr REF. */ + if (size > DWARF2_ADDR_SIZE || size == -1) + { + expansion_failed (loc, NULL_RTX, + "DWARF address size mismatch"); + return 0; + } + else if (size == DWARF2_ADDR_SIZE) + op = DW_OP_deref; + else + op = DW_OP_deref_size; -static dw_loc_list_ref -single_element_loc_list (dw_loc_descr_ref ref) -{ - return new_loc_list (ref, NULL, NULL, NULL, 0); + add_loc_descr (&descr, new_loc_descr (op, size, 0)); + } + + return descr; } /* Return dwarf representation of location list representing for - LOC_LIST of DECL. */ + LOC_LIST of DECL. WANT_ADDRESS has the same meaning as in + loc_list_from_tree function. */ static dw_loc_list_ref -dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) +dw_loc_list (var_loc_list * loc_list, tree decl, int want_address) { const char *endname, *secname; dw_loc_list_ref list; @@ -13670,8 +13945,6 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) dw_loc_descr_ref descr; char label_id[MAX_ARTIFICIAL_LABEL_BYTES]; - bool by_reference = decl_by_reference_p (decl); - /* Now that we know what section we are using for a base, actually construct the list of locations. The first location information is what is passed to the @@ -13684,28 +13957,14 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) a range of [last location start, end of function label]. */ node = loc_list->first; - varloc = NOTE_VAR_LOCATION (node->var_loc_note); secname = secname_for_decl (decl); if (NOTE_VAR_LOCATION_LOC (node->var_loc_note)) initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); else initialized = VAR_INIT_STATUS_INITIALIZED; - - if (!toplevel || by_reference) - { - gcc_assert (GET_CODE (varloc) == VAR_LOCATION); - /* Single part. */ - if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) - descr = loc_by_reference (mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0), - TYPE_MODE (TREE_TYPE (decl)), - initialized), - decl); - else - descr = NULL; - } - else - descr = loc_descriptor (varloc, DECL_MODE (decl), initialized); + varloc = NOTE_VAR_LOCATION (node->var_loc_note); + descr = dw_loc_list_1 (decl, varloc, want_address, initialized); if (loc_list && loc_list->first != loc_list->last) list = new_loc_list (descr, node->label, node->next->label, secname, 1); @@ -13721,22 +13980,9 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) { /* The variable has a location between NODE->LABEL and NODE->NEXT->LABEL. */ - enum var_init_status initialized = - NOTE_VAR_LOCATION_STATUS (node->var_loc_note); + initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note); - if (!toplevel || by_reference) - { - gcc_assert (GET_CODE (varloc) == VAR_LOCATION); - /* Single part. */ - if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) - descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0), - TYPE_MODE (TREE_TYPE (decl)), initialized); - else - descr = NULL; - descr = loc_by_reference (descr, decl); - } - else - descr = loc_descriptor (varloc, DECL_MODE (decl), initialized); + descr = dw_loc_list_1 (decl, varloc, want_address, initialized); add_loc_descr_to_loc_list (&list, descr, node->label, node->next->label, secname); } @@ -13745,9 +13991,6 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) it keeps its location until the end of function. */ if (NOTE_VAR_LOCATION_LOC (node->var_loc_note) != NULL_RTX) { - enum var_init_status initialized = - NOTE_VAR_LOCATION_STATUS (node->var_loc_note); - if (!current_function_decl) endname = text_end_label; else @@ -13757,20 +14000,9 @@ dw_loc_list (var_loc_list * loc_list, tree decl, bool toplevel) endname = ggc_strdup (label_id); } + initialized = NOTE_VAR_LOCATION_STATUS (node->var_loc_note); varloc = NOTE_VAR_LOCATION (node->var_loc_note); - if (!toplevel || by_reference) - { - gcc_assert (GET_CODE (varloc) == VAR_LOCATION); - /* Single part. */ - if (GET_CODE (XEXP (varloc, 1)) != PARALLEL) - descr = mem_loc_descriptor (XEXP (XEXP (varloc, 1), 0), - TYPE_MODE (TREE_TYPE (decl)), initialized); - else - descr = NULL; - descr = loc_by_reference (descr, decl); - } - else - descr = loc_descriptor (varloc, DECL_MODE (decl), initialized); + descr = dw_loc_list_1 (decl, varloc, want_address, initialized); add_loc_descr_to_loc_list (&list, descr, node->label, endname, secname); } return list; @@ -13948,11 +14180,7 @@ loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev) If WANT_ADDRESS is 1, expression computing address of LOC will be returned if WANT_ADDRESS is 2, expression computing address useable in location will be returned (i.e. DW_OP_reg can be used - to refer to register values) - TODO: Dwarf4 adds types to the stack machine that ought to be used here - DW_OP_stack_value will help in cases where we fail to find address of the - expression. - */ + to refer to register values). */ static dw_loc_list_ref loc_list_from_tree (tree loc, int want_address) @@ -14087,8 +14315,8 @@ loc_list_from_tree (tree loc, int want_address) var_loc_list *loc_list = lookup_decl_loc (loc); if (loc_list && loc_list->first - && (list_ret = dw_loc_list (loc_list, loc, want_address == 2))) - have_address = 1; + && (list_ret = dw_loc_list (loc_list, loc, want_address))) + have_address = want_address != 0; else if (rtl == NULL_RTX) { expansion_failed (loc, NULL_RTX, "DECL has no RTL"); @@ -15395,12 +15623,11 @@ fortran_common (tree decl, HOST_WIDE_INT *value) tree offset; int volatilep = 0, unsignedp = 0; - /* If the decl isn't a VAR_DECL, or if it isn't public or static, or if + /* If the decl isn't a VAR_DECL, or if it isn't static, or if it does not have a value (the offset into the common area), or if it is thread local (as opposed to global) then it isn't common, and shouldn't be handled as such. */ if (TREE_CODE (decl) != VAR_DECL - || !TREE_PUBLIC (decl) || !TREE_STATIC (decl) || !DECL_HAS_VALUE_EXPR_P (decl) || !is_fortran ()) @@ -15712,6 +15939,10 @@ tree_add_const_value_attribute_for_decl (dw_die_ref var_die, tree decl) else return false; + /* Don't add DW_AT_const_value if abstract origin already has one. */ + if (get_AT (var_die, DW_AT_const_value)) + return false; + return tree_add_const_value_attribute (var_die, DECL_INITIAL (decl)); } @@ -16249,7 +16480,9 @@ add_name_and_src_coords_attributes (dw_die_ref die, tree decl) decl_name = DECL_NAME (decl); if (decl_name != NULL && IDENTIFIER_POINTER (decl_name) != NULL) { - add_name_attribute (die, dwarf2_name (decl, 0)); + const char *name = dwarf2_name (decl, 0); + if (name) + add_name_attribute (die, name); if (! DECL_ARTIFICIAL (decl)) add_src_coords_attributes (die, decl); @@ -17038,12 +17271,10 @@ gen_formal_parameter_pack_die (tree parm_pack, gcc_assert (parm_pack && lang_hooks.function_parameter_pack_p (parm_pack) - && DECL_NAME (parm_pack) && subr_die); parm_pack_die = new_die (DW_TAG_GNU_formal_parameter_pack, subr_die, parm_pack); - add_AT_string (parm_pack_die, DW_AT_name, - IDENTIFIER_POINTER (DECL_NAME (parm_pack))); + add_src_coords_attributes (parm_pack_die, parm_pack); for (arg = pack_arg; arg; arg = TREE_CHAIN (arg)) { @@ -19009,7 +19240,11 @@ gen_namespace_die (tree decl, dw_die_ref context_die) context_die, decl); /* For Fortran modules defined in different CU don't add src coords. */ if (namespace_die->die_tag == DW_TAG_module && DECL_EXTERNAL (decl)) - add_name_attribute (namespace_die, dwarf2_name (decl, 0)); + { + const char *name = dwarf2_name (decl, 0); + if (name) + add_name_attribute (namespace_die, name); + } else add_name_and_src_coords_attributes (namespace_die, decl); if (DECL_EXTERNAL (decl)) @@ -19697,23 +19932,157 @@ dwarf2out_set_name (tree decl, tree name) { dw_die_ref die; dw_attr_ref attr; + const char *dname; die = TYPE_SYMTAB_DIE (decl); if (!die) return; + dname = dwarf2_name (name, 0); + if (!dname) + return; + attr = get_AT (die, DW_AT_name); if (attr) { struct indirect_string_node *node; - node = find_AT_string (dwarf2_name (name, 0)); + node = find_AT_string (dname); /* replace the string. */ attr->dw_attr_val.v.val_str = node; } else - add_name_attribute (die, dwarf2_name (name, 0)); + add_name_attribute (die, dname); +} + +/* Called by the final INSN scan whenever we see a direct function call. + Make an entry into the direct call table, recording the point of call + and a reference to the target function's debug entry. */ + +static void +dwarf2out_direct_call (tree targ) +{ + dcall_entry e; + tree origin = decl_ultimate_origin (targ); + + /* If this is a clone, use the abstract origin as the target. */ + if (origin) + targ = origin; + + e.poc_label_num = poc_label_num++; + e.poc_decl = current_function_decl; + e.targ_die = force_decl_die (targ); + VEC_safe_push (dcall_entry, gc, dcall_table, &e); + + /* Drop a label at the return point to mark the point of call. */ + ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); +} + +/* Returns a hash value for X (which really is a struct vcall_insn). */ + +static hashval_t +vcall_insn_table_hash (const void *x) +{ + return (hashval_t) ((const struct vcall_insn *) x)->insn_uid; +} + +/* Return nonzero if insn_uid of struct vcall_insn *X is the same as + insnd_uid of *Y. */ + +static int +vcall_insn_table_eq (const void *x, const void *y) +{ + return (((const struct vcall_insn *) x)->insn_uid + == ((const struct vcall_insn *) y)->insn_uid); +} + +/* Associate VTABLE_SLOT with INSN_UID in the VCALL_INSN_TABLE. */ + +static void +store_vcall_insn (unsigned int vtable_slot, int insn_uid) +{ + struct vcall_insn *item = GGC_NEW (struct vcall_insn); + struct vcall_insn **slot; + + gcc_assert (item); + item->insn_uid = insn_uid; + item->vtable_slot = vtable_slot; + slot = (struct vcall_insn **) + htab_find_slot_with_hash (vcall_insn_table, &item, + (hashval_t) insn_uid, INSERT); + *slot = item; +} + +/* Return the VTABLE_SLOT associated with INSN_UID. */ + +static unsigned int +lookup_vcall_insn (unsigned int insn_uid) +{ + struct vcall_insn item; + struct vcall_insn *p; + + item.insn_uid = insn_uid; + item.vtable_slot = 0; + p = (struct vcall_insn *) htab_find_with_hash (vcall_insn_table, + (void *) &item, + (hashval_t) insn_uid); + if (p == NULL) + return (unsigned int) -1; + return p->vtable_slot; +} + + +/* Called when lowering indirect calls to RTL. We make a note of INSN_UID + and the OBJ_TYPE_REF_TOKEN from ADDR. For C++ virtual calls, the token + is the vtable slot index that we will need to put in the virtual call + table later. */ + +static void +dwarf2out_virtual_call_token (tree addr, int insn_uid) +{ + if (is_cxx() && TREE_CODE (addr) == OBJ_TYPE_REF) + { + tree token = OBJ_TYPE_REF_TOKEN (addr); + if (TREE_CODE (token) == INTEGER_CST) + store_vcall_insn (TREE_INT_CST_LOW (token), insn_uid); + } +} + +/* Called when scheduling RTL, when a CALL_INSN is split. Copies the + OBJ_TYPE_REF_TOKEN previously associated with OLD_INSN and associates it + with NEW_INSN. */ + +static void +dwarf2out_copy_call_info (rtx old_insn, rtx new_insn) +{ + unsigned int vtable_slot = lookup_vcall_insn (INSN_UID (old_insn)); + + if (vtable_slot != (unsigned int) -1) + store_vcall_insn (vtable_slot, INSN_UID (new_insn)); +} + +/* Called by the final INSN scan whenever we see a virtual function call. + Make an entry into the virtual call table, recording the point of call + and the slot index of the vtable entry used to call the virtual member + function. The slot index was associated with the INSN_UID during the + lowering to RTL. */ + +static void +dwarf2out_virtual_call (int insn_uid) +{ + unsigned int vtable_slot = lookup_vcall_insn (insn_uid); + vcall_entry e; + + if (vtable_slot == (unsigned int) -1) + return; + + e.poc_label_num = poc_label_num++; + e.vtable_slot = vtable_slot; + VEC_safe_push (vcall_entry, gc, vcall_table, &e); + + /* Drop a label at the return point to mark the point of call. */ + ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LPOC", e.poc_label_num); } /* Called by the final INSN scan whenever we see a var location. We @@ -19751,8 +20120,7 @@ dwarf2out_var_location (rtx loc_note) ASM_OUTPUT_DEBUG_LABEL (asm_out_file, "LVL", loclabel_num); loclabel_num++; last_label = ggc_strdup (loclabel); - if (!NOTE_DURING_CALL_P (loc_note)) - last_postcall_label = NULL; + last_postcall_label = NULL; } newloc->var_loc_note = loc_note; newloc->next = NULL; @@ -20004,6 +20372,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) pubname_table = VEC_alloc (pubname_entry, gc, 32); pubtype_table = VEC_alloc (pubname_entry, gc, 32); + /* Allocate the table that maps insn UIDs to vtable slot indexes. */ + vcall_insn_table = htab_create_ggc (10, vcall_insn_table_hash, + vcall_insn_table_eq, NULL); + /* Generate the initial DIE for the .debug section. Note that the (string) value given in the DW_AT_name attribute of the DW_TAG_compile_unit DIE will (typically) be a relative pathname and that this pathname should be @@ -20032,6 +20404,10 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) SECTION_DEBUG, NULL); debug_pubtypes_section = get_section (DEBUG_PUBTYPES_SECTION, SECTION_DEBUG, NULL); + debug_dcall_section = get_section (DEBUG_DCALL_SECTION, + SECTION_DEBUG, NULL); + debug_vcall_section = get_section (DEBUG_VCALL_SECTION, + SECTION_DEBUG, NULL); debug_str_section = get_section (DEBUG_STR_SECTION, DEBUG_STR_SECTION_FLAGS, NULL); debug_ranges_section = get_section (DEBUG_RANGES_SECTION, @@ -20077,15 +20453,21 @@ dwarf2out_init (const char *filename ATTRIBUTE_UNUSED) ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label); } -#ifdef HAVE_GAS_CFI_SECTIONS_DIRECTIVE - if (dwarf2out_do_cfi_asm ()) +} + +/* Called before cgraph_optimize starts outputtting functions, variables + and toplevel asms into assembly. */ + +static void +dwarf2out_assembly_start (void) +{ + if (HAVE_GAS_CFI_SECTIONS_DIRECTIVE && dwarf2out_do_cfi_asm ()) { #ifndef TARGET_UNWIND_INFO if (USING_SJLJ_EXCEPTIONS || (!flag_unwind_tables && !flag_exceptions)) #endif fprintf (asm_out_file, "\t.cfi_sections\t.debug_frame\n"); } -#endif } /* A helper function for dwarf2out_finish called through @@ -20406,6 +20788,7 @@ prune_unused_types (void) limbo_die_node *node; comdat_type_node *ctnode; pubname_ref pub; + dcall_entry *dcall; #if ENABLE_ASSERT_CHECKING /* All the marks should already be clear. */ @@ -20436,6 +20819,10 @@ prune_unused_types (void) for (i = 0; i < arange_table_in_use; i++) prune_unused_types_mark (arange_table[i], 1); + /* Mark nodes referenced from the direct call table. */ + for (i = 0; VEC_iterate (dcall_entry, dcall_table, i, dcall); i++) + prune_unused_types_mark (dcall->targ_die, 1); + /* Get rid of nodes that aren't marked; and update the string counts. */ if (debug_str_hash && debug_str_hash_forced) htab_traverse (debug_str_hash, prune_indirect_string, NULL); @@ -20897,6 +21284,18 @@ dwarf2out_finish (const char *filename) output_pubnames (pubtype_table); } + /* Output direct and virtual call tables if necessary. */ + if (!VEC_empty (dcall_entry, dcall_table)) + { + switch_to_section (debug_dcall_section); + output_dcall_table (); + } + if (!VEC_empty (vcall_entry, vcall_table)) + { + switch_to_section (debug_vcall_section); + output_vcall_table (); + } + /* Output the address range information. We only put functions in the arange table, so don't write it out if we don't have any. */ if (fde_table_in_use) @@ -20944,6 +21343,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = { 0, /* init */ 0, /* finish */ + 0, /* assembly_start */ 0, /* define */ 0, /* undef */ 0, /* start_source_file */ @@ -20967,6 +21367,10 @@ const struct gcc_debug_hooks dwarf2_debug_hooks = 0, /* handle_pch */ 0, /* var_location */ 0, /* switch_text_section */ + 0, /* direct_call */ + 0, /* virtual_call_token */ + 0, /* copy_call_info */ + 0, /* virtual_call */ 0, /* set_name */ 0 /* start_end_main_source_file */ }; diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c index b3672e3e5ad..674bcc4e4b9 100644 --- a/gcc/emit-rtl.c +++ b/gcc/emit-rtl.c @@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-pass.h" #include "df.h" #include "params.h" +#include "target.h" /* Commonly used modes. */ @@ -193,7 +194,7 @@ static rtx lookup_const_fixed (rtx); static hashval_t mem_attrs_htab_hash (const void *); static int mem_attrs_htab_eq (const void *, const void *); static mem_attrs *get_mem_attrs (alias_set_type, tree, rtx, rtx, unsigned int, - enum machine_mode); + addr_space_t, enum machine_mode); static hashval_t reg_attrs_htab_hash (const void *); static int reg_attrs_htab_eq (const void *, const void *); static reg_attrs *get_reg_attrs (tree, int); @@ -292,6 +293,7 @@ mem_attrs_htab_hash (const void *x) const mem_attrs *const p = (const mem_attrs *) x; return (p->alias ^ (p->align * 1000) + ^ (p->addrspace * 4000) ^ ((p->offset ? INTVAL (p->offset) : 0) * 50000) ^ ((p->size ? INTVAL (p->size) : 0) * 2500000) ^ (size_t) iterative_hash_expr (p->expr, 0)); @@ -309,6 +311,7 @@ mem_attrs_htab_eq (const void *x, const void *y) return (p->alias == q->alias && p->offset == q->offset && p->size == q->size && p->align == q->align + && p->addrspace == q->addrspace && (p->expr == q->expr || (p->expr != NULL_TREE && q->expr != NULL_TREE && operand_equal_p (p->expr, q->expr, 0)))); @@ -320,7 +323,7 @@ mem_attrs_htab_eq (const void *x, const void *y) static mem_attrs * get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, - unsigned int align, enum machine_mode mode) + unsigned int align, addr_space_t addrspace, enum machine_mode mode) { mem_attrs attrs; void **slot; @@ -328,7 +331,7 @@ get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, /* If everything is the default, we can just return zero. This must match what the corresponding MEM_* macros return when the field is not present. */ - if (alias == 0 && expr == 0 && offset == 0 + if (alias == 0 && expr == 0 && offset == 0 && addrspace == 0 && (size == 0 || (mode != BLKmode && GET_MODE_SIZE (mode) == INTVAL (size))) && (STRICT_ALIGNMENT && mode != BLKmode @@ -340,6 +343,7 @@ get_mem_attrs (alias_set_type alias, tree expr, rtx offset, rtx size, attrs.offset = offset; attrs.size = size; attrs.align = align; + attrs.addrspace = addrspace; slot = htab_find_slot (mem_attrs_htab, &attrs, INSERT); if (*slot == 0) @@ -1386,7 +1390,9 @@ operand_subword (rtx op, unsigned int offset, int validate_address, enum machine else if (reload_completed) { - if (! strict_memory_address_p (word_mode, XEXP (new_rtx, 0))) + if (! strict_memory_address_addr_space_p (word_mode, + XEXP (new_rtx, 0), + MEM_ADDR_SPACE (op))) return 0; } else @@ -1795,7 +1801,8 @@ set_mem_attributes_minus_bitpos (rtx ref, tree t, int objectp, /* Now set the attributes we computed above. */ MEM_ATTRS (ref) - = get_mem_attrs (alias, expr, offset, size, align, GET_MODE (ref)); + = get_mem_attrs (alias, expr, offset, size, align, + TYPE_ADDR_SPACE (type), GET_MODE (ref)); /* If this is already known to be a scalar or aggregate, we are done. */ if (MEM_IN_STRUCT_P (ref) || MEM_SCALAR_P (ref)) @@ -1827,7 +1834,17 @@ set_mem_alias_set (rtx mem, alias_set_type set) MEM_ATTRS (mem) = get_mem_attrs (set, MEM_EXPR (mem), MEM_OFFSET (mem), MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); +} + +/* Set the address space of MEM to ADDRSPACE (target-defined). */ + +void +set_mem_addr_space (rtx mem, addr_space_t addrspace) +{ + MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), + MEM_OFFSET (mem), MEM_SIZE (mem), + MEM_ALIGN (mem), addrspace, GET_MODE (mem)); } /* Set the alignment of MEM to ALIGN bits. */ @@ -1837,7 +1854,7 @@ set_mem_align (rtx mem, unsigned int align) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), MEM_OFFSET (mem), MEM_SIZE (mem), align, - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the expr for MEM to EXPR. */ @@ -1847,7 +1864,8 @@ set_mem_expr (rtx mem, tree expr) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), expr, MEM_OFFSET (mem), - MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem)); + MEM_SIZE (mem), MEM_ALIGN (mem), + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the offset of MEM to OFFSET. */ @@ -1857,7 +1875,7 @@ set_mem_offset (rtx mem, rtx offset) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), offset, MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Set the size of MEM to SIZE. */ @@ -1867,7 +1885,7 @@ set_mem_size (rtx mem, rtx size) { MEM_ATTRS (mem) = get_mem_attrs (MEM_ALIAS_SET (mem), MEM_EXPR (mem), MEM_OFFSET (mem), size, MEM_ALIGN (mem), - GET_MODE (mem)); + MEM_ADDR_SPACE (mem), GET_MODE (mem)); } /* Return a memory reference like MEMREF, but with its mode changed to MODE @@ -1879,23 +1897,25 @@ set_mem_size (rtx mem, rtx size) static rtx change_address_1 (rtx memref, enum machine_mode mode, rtx addr, int validate) { + addr_space_t as; rtx new_rtx; gcc_assert (MEM_P (memref)); + as = MEM_ADDR_SPACE (memref); if (mode == VOIDmode) mode = GET_MODE (memref); if (addr == 0) addr = XEXP (memref, 0); if (mode == GET_MODE (memref) && addr == XEXP (memref, 0) - && (!validate || memory_address_p (mode, addr))) + && (!validate || memory_address_addr_space_p (mode, addr, as))) return memref; if (validate) { if (reload_in_progress || reload_completed) - gcc_assert (memory_address_p (mode, addr)); + gcc_assert (memory_address_addr_space_p (mode, addr, as)); else - addr = memory_address (mode, addr); + addr = memory_address_addr_space (mode, addr, as); } if (rtx_equal_p (addr, XEXP (memref, 0)) && mode == GET_MODE (memref)) @@ -1934,7 +1954,8 @@ change_address (rtx memref, enum machine_mode mode, rtx addr) } MEM_ATTRS (new_rtx) - = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, mmode); + = get_mem_attrs (MEM_ALIAS_SET (memref), 0, 0, size, align, + MEM_ADDR_SPACE (memref), mmode); return new_rtx; } @@ -1954,11 +1975,13 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, rtx memoffset = MEM_OFFSET (memref); rtx size = 0; unsigned int memalign = MEM_ALIGN (memref); + addr_space_t as = MEM_ADDR_SPACE (memref); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); int pbits; /* If there are no changes, just return the original memory reference. */ if (mode == GET_MODE (memref) && !offset - && (!validate || memory_address_p (mode, addr))) + && (!validate || memory_address_addr_space_p (mode, addr, as))) return memref; /* ??? Prefer to create garbage instead of creating shared rtl. @@ -1968,7 +1991,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, /* Convert a possibly large offset to a signed value within the range of the target address space. */ - pbits = GET_MODE_BITSIZE (Pmode); + pbits = GET_MODE_BITSIZE (address_mode); if (HOST_BITS_PER_WIDE_INT > pbits) { int shift = HOST_BITS_PER_WIDE_INT - pbits; @@ -1984,7 +2007,7 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, && offset >= 0 && (unsigned HOST_WIDE_INT) offset < GET_MODE_ALIGNMENT (GET_MODE (memref)) / BITS_PER_UNIT) - addr = gen_rtx_LO_SUM (Pmode, XEXP (addr, 0), + addr = gen_rtx_LO_SUM (address_mode, XEXP (addr, 0), plus_constant (XEXP (addr, 1), offset)); else addr = plus_constant (addr, offset); @@ -2017,7 +2040,8 @@ adjust_address_1 (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset, size = plus_constant (MEM_SIZE (memref), -offset); MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), - memoffset, size, memalign, GET_MODE (new_rtx)); + memoffset, size, memalign, as, + GET_MODE (new_rtx)); /* At some point, we should validate that this offset is within the object, if all the appropriate values are known. */ @@ -2045,8 +2069,10 @@ rtx offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) { rtx new_rtx, addr = XEXP (memref, 0); + addr_space_t as = MEM_ADDR_SPACE (memref); + enum machine_mode address_mode = targetm.addr_space.address_mode (as); - new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset); + new_rtx = simplify_gen_binary (PLUS, address_mode, addr, offset); /* At this point we don't know _why_ the address is invalid. It could have secondary memory references, multiplies or anything. @@ -2055,12 +2081,12 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) being able to recognize the magic around pic_offset_table_rtx. This stuff is fragile, and is yet another example of why it is bad to expose PIC machinery too early. */ - if (! memory_address_p (GET_MODE (memref), new_rtx) + if (! memory_address_addr_space_p (GET_MODE (memref), new_rtx, as) && GET_CODE (addr) == PLUS && XEXP (addr, 0) == pic_offset_table_rtx) { addr = force_reg (GET_MODE (addr), addr); - new_rtx = simplify_gen_binary (PLUS, Pmode, addr, offset); + new_rtx = simplify_gen_binary (PLUS, address_mode, addr, offset); } update_temp_slot_address (XEXP (memref, 0), new_rtx); @@ -2075,7 +2101,7 @@ offset_address (rtx memref, rtx offset, unsigned HOST_WIDE_INT pow2) MEM_ATTRS (new_rtx) = get_mem_attrs (MEM_ALIAS_SET (memref), MEM_EXPR (memref), 0, 0, MIN (MEM_ALIGN (memref), pow2 * BITS_PER_UNIT), - GET_MODE (new_rtx)); + as, GET_MODE (new_rtx)); return new_rtx; } @@ -2179,7 +2205,8 @@ widen_memory_access (rtx memref, enum machine_mode mode, HOST_WIDE_INT offset) /* ??? Maybe use get_alias_set on any remaining expression. */ MEM_ATTRS (new_rtx) = get_mem_attrs (0, expr, memoffset, GEN_INT (size), - MEM_ALIGN (new_rtx), mode); + MEM_ALIGN (new_rtx), + MEM_ADDR_SPACE (new_rtx), mode); return new_rtx; } @@ -2207,7 +2234,7 @@ get_spill_slot_decl (bool force_build_p) rd = gen_rtx_MEM (BLKmode, frame_pointer_rtx); MEM_NOTRAP_P (rd) = 1; MEM_ATTRS (rd) = get_mem_attrs (new_alias_set (), d, const0_rtx, - NULL_RTX, 0, BLKmode); + NULL_RTX, 0, ADDR_SPACE_GENERIC, BLKmode); SET_DECL_RTL (d, rd); return d; @@ -2240,7 +2267,7 @@ set_mem_attrs_for_spill (rtx mem) MEM_ATTRS (mem) = get_mem_attrs (alias, expr, offset, MEM_SIZE (mem), MEM_ALIGN (mem), - GET_MODE (mem)); + ADDR_SPACE_GENERIC, GET_MODE (mem)); MEM_NOTRAP_P (mem) = 1; } @@ -2393,6 +2420,8 @@ verify_rtx_sharing (rtx orig, rtx insn) switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -2593,6 +2622,8 @@ repeat: switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -2712,6 +2743,8 @@ repeat: switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -2783,6 +2816,8 @@ set_used_flags (rtx x) switch (code) { case REG: + case DEBUG_EXPR: + case VALUE: case CONST_INT: case CONST_DOUBLE: case CONST_FIXED: @@ -3481,6 +3516,10 @@ try_split (rtx pat, rtx trial, int last) p = &XEXP (*p, 1); *p = CALL_INSN_FUNCTION_USAGE (trial); SIBLING_CALL_P (insn) = SIBLING_CALL_P (trial); + + /* Update the debug information for the CALL_INSN. */ + if (flag_enable_icf_debug) + (*debug_hooks->copy_call_info) (trial, insn); } } diff --git a/gcc/emit-rtl.h b/gcc/emit-rtl.h index ad96181af40..01479e1eb5f 100644 --- a/gcc/emit-rtl.h +++ b/gcc/emit-rtl.h @@ -26,6 +26,9 @@ extern void set_mem_alias_set (rtx, alias_set_type); /* Set the alignment of MEM to ALIGN bits. */ extern void set_mem_align (rtx, unsigned int); +/* Set the address space of MEM to ADDRSPACE. */ +extern void set_mem_addr_space (rtx, addr_space_t); + /* Set the expr for MEM to EXPR. */ extern void set_mem_expr (rtx, tree); diff --git a/gcc/except.c b/gcc/except.c index bb26bf4dc6f..b25e48b6c9b 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -552,8 +552,11 @@ duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data, case ERT_ALLOWED_EXCEPTIONS: new_r->u.allowed.type_list = old_r->u.allowed.type_list; - new_r->u.allowed.label - = data->label_map (old_r->u.allowed.label, data->label_map_data); + if (old_r->u.allowed.label) + new_r->u.allowed.label + = data->label_map (old_r->u.allowed.label, data->label_map_data); + else + new_r->u.allowed.label = NULL_TREE; break; case ERT_MUST_NOT_THROW: @@ -2886,7 +2889,14 @@ output_ttype (tree type, int tt_format, int tt_format_size) { struct varpool_node *node; - type = lookup_type_for_runtime (type); + /* FIXME lto. pass_ipa_free_lang_data changes all types to + runtime types so TYPE should already be a runtime type + reference. When pass_ipa_free_lang data is made a default + pass, we can then remove the call to lookup_type_for_runtime + below. */ + if (TYPE_P (type)) + type = lookup_type_for_runtime (type); + value = expand_expr (type, NULL_RTX, VOIDmode, EXPAND_INITIALIZER); /* Let cgraph know that the rtti decl is used. Not all of the diff --git a/gcc/explow.c b/gcc/explow.c index 3073ff0eb91..0bbbc003f6d 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see static rtx break_out_memory_refs (rtx); static void emit_stack_probe (rtx); +static void anti_adjust_stack_and_probe (rtx); /* Truncate and perhaps sign-extend C as appropriate for MODE. */ @@ -306,27 +307,27 @@ break_out_memory_refs (rtx x) rtx op1 = break_out_memory_refs (XEXP (x, 1)); if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1)) - x = simplify_gen_binary (GET_CODE (x), Pmode, op0, op1); + x = simplify_gen_binary (GET_CODE (x), GET_MODE (x), op0, op1); } return x; } -/* Given X, a memory address in ptr_mode, convert it to an address - in Pmode, or vice versa (TO_MODE says which way). We take advantage of - the fact that pointers are not allowed to overflow by commuting arithmetic - operations over conversions so that address arithmetic insns can be - used. */ +/* Given X, a memory address in address space AS' pointer mode, convert it to + an address in the address space's address mode, or vice versa (TO_MODE says + which way). We take advantage of the fact that pointers are not allowed to + overflow by commuting arithmetic operations over conversions so that address + arithmetic insns can be used. */ rtx -convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, - rtx x) +convert_memory_address_addr_space (enum machine_mode to_mode ATTRIBUTE_UNUSED, + rtx x, addr_space_t as ATTRIBUTE_UNUSED) { #ifndef POINTERS_EXTEND_UNSIGNED gcc_assert (GET_MODE (x) == to_mode || GET_MODE (x) == VOIDmode); return x; #else /* defined(POINTERS_EXTEND_UNSIGNED) */ - enum machine_mode from_mode; + enum machine_mode pointer_mode, address_mode, from_mode; rtx temp; enum rtx_code code; @@ -334,7 +335,9 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, if (GET_MODE (x) == to_mode) return x; - from_mode = to_mode == ptr_mode ? Pmode : ptr_mode; + pointer_mode = targetm.addr_space.pointer_mode (as); + address_mode = targetm.addr_space.address_mode (as); + from_mode = to_mode == pointer_mode ? address_mode : pointer_mode; /* Here we handle some special cases. If none of them apply, fall through to the default case. */ @@ -375,7 +378,8 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, case CONST: return gen_rtx_CONST (to_mode, - convert_memory_address (to_mode, XEXP (x, 0))); + convert_memory_address_addr_space + (to_mode, XEXP (x, 0), as)); break; case PLUS: @@ -389,10 +393,12 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, if (GET_MODE_SIZE (to_mode) < GET_MODE_SIZE (from_mode) || (GET_CODE (x) == PLUS && CONST_INT_P (XEXP (x, 1)) - && (XEXP (x, 1) == convert_memory_address (to_mode, XEXP (x, 1)) + && (XEXP (x, 1) == convert_memory_address_addr_space + (to_mode, XEXP (x, 1), as) || POINTERS_EXTEND_UNSIGNED < 0))) return gen_rtx_fmt_ee (GET_CODE (x), to_mode, - convert_memory_address (to_mode, XEXP (x, 0)), + convert_memory_address_addr_space + (to_mode, XEXP (x, 0), as), XEXP (x, 1)); break; @@ -405,21 +411,22 @@ convert_memory_address (enum machine_mode to_mode ATTRIBUTE_UNUSED, #endif /* defined(POINTERS_EXTEND_UNSIGNED) */ } -/* Return something equivalent to X but valid as a memory address - for something of mode MODE. When X is not itself valid, this - works by copying X or subexpressions of it into registers. */ +/* Return something equivalent to X but valid as a memory address for something + of mode MODE in the named address space AS. When X is not itself valid, + this works by copying X or subexpressions of it into registers. */ rtx -memory_address (enum machine_mode mode, rtx x) +memory_address_addr_space (enum machine_mode mode, rtx x, addr_space_t as) { rtx oldx = x; + enum machine_mode address_mode = targetm.addr_space.address_mode (as); - x = convert_memory_address (Pmode, x); + x = convert_memory_address_addr_space (address_mode, x, as); /* By passing constant addresses through registers we get a chance to cse them. */ if (! cse_not_expected && CONSTANT_P (x) && CONSTANT_ADDRESS_P (x)) - x = force_reg (Pmode, x); + x = force_reg (address_mode, x); /* We get better cse by rejecting indirect addressing at this stage. Let the combiner create indirect addresses where appropriate. @@ -431,12 +438,12 @@ memory_address (enum machine_mode mode, rtx x) x = break_out_memory_refs (x); /* At this point, any valid address is accepted. */ - if (memory_address_p (mode, x)) + if (memory_address_addr_space_p (mode, x, as)) goto done; /* If it was valid before but breaking out memory refs invalidated it, use it the old way. */ - if (memory_address_p (mode, oldx)) + if (memory_address_addr_space_p (mode, oldx, as)) { x = oldx; goto done; @@ -447,9 +454,9 @@ memory_address (enum machine_mode mode, rtx x) below can handle all possible cases, but machine-dependent transformations can make better code. */ { - rtx orig_x = x; - x = targetm.legitimize_address (x, oldx, mode); - if (orig_x != x && memory_address_p (mode, x)) + rtx orig_x = x; + x = targetm.addr_space.legitimize_address (x, oldx, mode, as); + if (orig_x != x && memory_address_addr_space_p (mode, x, as)) goto done; } @@ -467,12 +474,12 @@ memory_address (enum machine_mode mode, rtx x) rtx constant_term = const0_rtx; rtx y = eliminate_constant_term (x, &constant_term); if (constant_term == const0_rtx - || ! memory_address_p (mode, y)) + || ! memory_address_addr_space_p (mode, y, as)) x = force_operand (x, NULL_RTX); else { y = gen_rtx_PLUS (GET_MODE (x), copy_to_reg (y), constant_term); - if (! memory_address_p (mode, y)) + if (! memory_address_addr_space_p (mode, y, as)) x = force_operand (x, NULL_RTX); else x = y; @@ -490,12 +497,12 @@ memory_address (enum machine_mode mode, rtx x) /* Last resort: copy the value to a register, since the register is a valid address. */ else - x = force_reg (Pmode, x); + x = force_reg (address_mode, x); } done: - gcc_assert (memory_address_p (mode, x)); + gcc_assert (memory_address_addr_space_p (mode, x, as)); /* If we didn't change the address, we are done. Otherwise, mark a reg as a pointer if we have REG or REG + CONST_INT. */ if (oldx == x) @@ -523,7 +530,8 @@ validize_mem (rtx ref) if (!MEM_P (ref)) return ref; ref = use_anchored_address (ref); - if (memory_address_p (GET_MODE (ref), XEXP (ref, 0))) + if (memory_address_addr_space_p (GET_MODE (ref), XEXP (ref, 0), + MEM_ADDR_SPACE (ref))) return ref; /* Don't alter REF itself, since that is probably a stack slot. */ @@ -800,7 +808,8 @@ promote_mode (const_tree type ATTRIBUTE_UNUSED, enum machine_mode mode, case REFERENCE_TYPE: case POINTER_TYPE: *punsignedp = POINTERS_EXTEND_UNSIGNED; - return Pmode; + return targetm.addr_space.address_mode + (TYPE_ADDR_SPACE (TREE_TYPE (type))); break; #endif @@ -1225,9 +1234,11 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align) gcc_assert (!(stack_pointer_delta % (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT))); - /* If needed, check that we have the required amount of stack. - Take into account what has already been checked. */ - if (flag_stack_check == GENERIC_STACK_CHECK) + /* If needed, check that we have the required amount of stack. Take into + account what has already been checked. */ + if (STACK_CHECK_MOVING_SP) + ; + else if (flag_stack_check == GENERIC_STACK_CHECK) probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE, size); else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK) @@ -1296,7 +1307,10 @@ allocate_dynamic_stack_space (rtx size, rtx target, int known_align) emit_label (space_available); } - anti_adjust_stack (size); + if (flag_stack_check && STACK_CHECK_MOVING_SP) + anti_adjust_stack_and_probe (size); + else + anti_adjust_stack (size); #ifdef STACK_GROWS_DOWNWARD emit_move_insn (target, virtual_stack_dynamic_rtx); @@ -1347,6 +1361,12 @@ emit_stack_probe (rtx address) MEM_VOLATILE_P (memref) = 1; + /* See if we have an insn to probe the stack. */ +#ifdef HAVE_probe_stack + if (HAVE_probe_stack) + emit_insn (gen_probe_stack (memref)); + else +#endif if (STACK_CHECK_PROBE_LOAD) emit_move_insn (gen_reg_rtx (word_mode), memref); else @@ -1354,15 +1374,20 @@ emit_stack_probe (rtx address) } /* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive. - FIRST is a constant and size is a Pmode RTX. These are offsets from the - current stack pointer. STACK_GROWS_DOWNWARD says whether to add or - subtract from the stack. If SIZE is constant, this is done - with a fixed number of probes. Otherwise, we must make a loop. */ + FIRST is a constant and size is a Pmode RTX. These are offsets from + the current stack pointer. STACK_GROWS_DOWNWARD says whether to add + or subtract them from the stack pointer. */ + +#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP) #ifdef STACK_GROWS_DOWNWARD #define STACK_GROW_OP MINUS +#define STACK_GROW_OPTAB sub_optab +#define STACK_GROW_OFF(off) -(off) #else #define STACK_GROW_OP PLUS +#define STACK_GROW_OPTAB add_optab +#define STACK_GROW_OFF(off) (off) #endif void @@ -1372,113 +1397,272 @@ probe_stack_range (HOST_WIDE_INT first, rtx size) if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode) size = convert_to_mode (Pmode, size, 1); - /* Next see if the front end has set up a function for us to call to - check the stack. */ - if (stack_check_libfunc != 0) + /* Next see if we have a function to check the stack. */ + if (stack_check_libfunc) { - rtx addr = memory_address (QImode, + rtx addr = memory_address (Pmode, gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, stack_pointer_rtx, plus_constant (size, first))); - - addr = convert_memory_address (ptr_mode, addr); - emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr, - ptr_mode); + emit_library_call (stack_check_libfunc, LCT_NORMAL, VOIDmode, 1, addr); } - /* Next see if we have an insn to check the stack. Use it if so. */ + /* Next see if we have an insn to check the stack. */ #ifdef HAVE_check_stack else if (HAVE_check_stack) { - insn_operand_predicate_fn pred; - rtx last_addr - = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - plus_constant (size, first)), - NULL_RTX); - - pred = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate; - if (pred && ! ((*pred) (last_addr, Pmode))) - last_addr = copy_to_mode_reg (Pmode, last_addr); + rtx addr = memory_address (Pmode, + gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + stack_pointer_rtx, + plus_constant (size, first))); + insn_operand_predicate_fn pred + = insn_data[(int) CODE_FOR_check_stack].operand[0].predicate; + if (pred && !((*pred) (addr, Pmode))) + addr = copy_to_mode_reg (Pmode, addr); - emit_insn (gen_check_stack (last_addr)); + emit_insn (gen_check_stack (addr)); } #endif - /* If we have to generate explicit probes, see if we have a constant - small number of them to generate. If so, that's the easy case. */ - else if (CONST_INT_P (size) - && INTVAL (size) < 10 * STACK_CHECK_PROBE_INTERVAL) + /* Otherwise we have to generate explicit probes. If we have a constant + small number of them to generate, that's the easy case. */ + else if (CONST_INT_P (size) && INTVAL (size) < 7 * PROBE_INTERVAL) { - HOST_WIDE_INT offset; - - /* Start probing at FIRST + N * STACK_CHECK_PROBE_INTERVAL - for values of N from 1 until it exceeds LAST. If only one - probe is needed, this will not generate any code. Then probe - at LAST. */ - for (offset = first + STACK_CHECK_PROBE_INTERVAL; - offset < INTVAL (size); - offset = offset + STACK_CHECK_PROBE_INTERVAL) - emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - GEN_INT (offset))); - - emit_stack_probe (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - plus_constant (size, first))); + HOST_WIDE_INT isize = INTVAL (size), i; + rtx addr; + + /* Probe at FIRST + N * PROBE_INTERVAL for values of N from 1 until + it exceeds SIZE. If only one probe is needed, this will not + generate any code. Then probe at FIRST + SIZE. */ + for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL) + { + addr = memory_address (Pmode, + plus_constant (stack_pointer_rtx, + STACK_GROW_OFF (first + i))); + emit_stack_probe (addr); + } + + addr = memory_address (Pmode, + plus_constant (stack_pointer_rtx, + STACK_GROW_OFF (first + isize))); + emit_stack_probe (addr); } - /* In the variable case, do the same as above, but in a loop. We emit loop - notes so that loop optimization can be done. */ + /* In the variable case, do the same as above, but in a loop. Note that we + must be extra careful with variables wrapping around because we might be + at the very top (or the very bottom) of the address space and we have to + be able to handle this case properly; in particular, we use an equality + test for the loop condition. */ else { - rtx test_addr - = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - GEN_INT (first + STACK_CHECK_PROBE_INTERVAL)), - NULL_RTX); - rtx last_addr - = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, - stack_pointer_rtx, - plus_constant (size, first)), - NULL_RTX); - rtx incr = GEN_INT (STACK_CHECK_PROBE_INTERVAL); + rtx rounded_size, rounded_size_op, test_addr, last_addr, temp; rtx loop_lab = gen_label_rtx (); - rtx test_lab = gen_label_rtx (); rtx end_lab = gen_label_rtx (); - rtx temp; - if (!REG_P (test_addr) - || REGNO (test_addr) < FIRST_PSEUDO_REGISTER) - test_addr = force_reg (Pmode, test_addr); - emit_jump (test_lab); + /* Step 1: round SIZE to the previous multiple of the interval. */ + + /* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */ + rounded_size + = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL)); + rounded_size_op = force_operand (rounded_size, NULL_RTX); + + + /* Step 2: compute initial and final value of the loop counter. */ + + /* TEST_ADDR = SP + FIRST. */ + test_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + stack_pointer_rtx, + GEN_INT (first)), NULL_RTX); + + /* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */ + last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + test_addr, + rounded_size_op), NULL_RTX); + + + /* Step 3: the loop + + while (TEST_ADDR != LAST_ADDR) + { + TEST_ADDR = TEST_ADDR + PROBE_INTERVAL + probe at TEST_ADDR + } + + probes at FIRST + N * PROBE_INTERVAL for values of N from 1 + until it is equal to ROUNDED_SIZE. */ emit_label (loop_lab); - emit_stack_probe (test_addr); -#ifdef STACK_GROWS_DOWNWARD -#define CMP_OPCODE GTU - temp = expand_binop (Pmode, sub_optab, test_addr, incr, test_addr, - 1, OPTAB_WIDEN); -#else -#define CMP_OPCODE LTU - temp = expand_binop (Pmode, add_optab, test_addr, incr, test_addr, + /* Jump to END_LAB if TEST_ADDR == LAST_ADDR. */ + emit_cmp_and_jump_insns (test_addr, last_addr, EQ, NULL_RTX, Pmode, 1, + end_lab); + + /* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */ + temp = expand_binop (Pmode, STACK_GROW_OPTAB, test_addr, + GEN_INT (PROBE_INTERVAL), test_addr, 1, OPTAB_WIDEN); -#endif gcc_assert (temp == test_addr); - emit_label (test_lab); - emit_cmp_and_jump_insns (test_addr, last_addr, CMP_OPCODE, - NULL_RTX, Pmode, 1, loop_lab); - emit_jump (end_lab); + /* Probe at TEST_ADDR. */ + emit_stack_probe (test_addr); + + emit_jump (loop_lab); + emit_label (end_lab); - emit_stack_probe (last_addr); + + /* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time + that SIZE is equal to ROUNDED_SIZE. */ + + /* TEMP = SIZE - ROUNDED_SIZE. */ + temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size); + if (temp != const0_rtx) + { + rtx addr; + + if (GET_CODE (temp) == CONST_INT) + { + /* Use [base + disp} addressing mode if supported. */ + HOST_WIDE_INT offset = INTVAL (temp); + addr = memory_address (Pmode, + plus_constant (last_addr, + STACK_GROW_OFF (offset))); + } + else + { + /* Manual CSE if the difference is not known at compile-time. */ + temp = gen_rtx_MINUS (Pmode, size, rounded_size_op); + addr = memory_address (Pmode, + gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + last_addr, temp)); + } + + emit_stack_probe (addr); + } } } - + +/* Adjust the stack by SIZE bytes while probing it. Note that we skip the + probe for the first interval + a small dope of 4 words and instead probe + that many bytes past the specified size to maintain a protection area. */ + +static void +anti_adjust_stack_and_probe (rtx size) +{ + const int dope = 4 * UNITS_PER_WORD; + + /* First ensure SIZE is Pmode. */ + if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode) + size = convert_to_mode (Pmode, size, 1); + + /* If we have a constant small number of probes to generate, that's the + easy case. */ + if (GET_CODE (size) == CONST_INT && INTVAL (size) < 7 * PROBE_INTERVAL) + { + HOST_WIDE_INT isize = INTVAL (size), i; + bool first_probe = true; + + /* Adjust SP and probe to PROBE_INTERVAL + N * PROBE_INTERVAL for + values of N from 1 until it exceeds SIZE. If only one probe is + needed, this will not generate any code. Then adjust and probe + to PROBE_INTERVAL + SIZE. */ + for (i = PROBE_INTERVAL; i < isize; i += PROBE_INTERVAL) + { + if (first_probe) + { + anti_adjust_stack (GEN_INT (2 * PROBE_INTERVAL + dope)); + first_probe = false; + } + else + anti_adjust_stack (GEN_INT (PROBE_INTERVAL)); + emit_stack_probe (stack_pointer_rtx); + } + + if (first_probe) + anti_adjust_stack (plus_constant (size, PROBE_INTERVAL + dope)); + else + anti_adjust_stack (plus_constant (size, PROBE_INTERVAL - i)); + emit_stack_probe (stack_pointer_rtx); + } + + /* In the variable case, do the same as above, but in a loop. Note that we + must be extra careful with variables wrapping around because we might be + at the very top (or the very bottom) of the address space and we have to + be able to handle this case properly; in particular, we use an equality + test for the loop condition. */ + else + { + rtx rounded_size, rounded_size_op, last_addr, temp; + rtx loop_lab = gen_label_rtx (); + rtx end_lab = gen_label_rtx (); + + + /* Step 1: round SIZE to the previous multiple of the interval. */ + + /* ROUNDED_SIZE = SIZE & -PROBE_INTERVAL */ + rounded_size + = simplify_gen_binary (AND, Pmode, size, GEN_INT (-PROBE_INTERVAL)); + rounded_size_op = force_operand (rounded_size, NULL_RTX); + + + /* Step 2: compute initial and final value of the loop counter. */ + + /* SP = SP_0 + PROBE_INTERVAL. */ + anti_adjust_stack (GEN_INT (PROBE_INTERVAL + dope)); + + /* LAST_ADDR = SP_0 + PROBE_INTERVAL + ROUNDED_SIZE. */ + last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode, + stack_pointer_rtx, + rounded_size_op), NULL_RTX); + + + /* Step 3: the loop + + while (SP != LAST_ADDR) + { + SP = SP + PROBE_INTERVAL + probe at SP + } + + adjusts SP and probes to PROBE_INTERVAL + N * PROBE_INTERVAL for + values of N from 1 until it is equal to ROUNDED_SIZE. */ + + emit_label (loop_lab); + + /* Jump to END_LAB if SP == LAST_ADDR. */ + emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX, + Pmode, 1, end_lab); + + /* SP = SP + PROBE_INTERVAL and probe at SP. */ + anti_adjust_stack (GEN_INT (PROBE_INTERVAL)); + emit_stack_probe (stack_pointer_rtx); + + emit_jump (loop_lab); + + emit_label (end_lab); + + + /* Step 4: adjust SP and probe to PROBE_INTERVAL + SIZE if we cannot + assert at compile-time that SIZE is equal to ROUNDED_SIZE. */ + + /* TEMP = SIZE - ROUNDED_SIZE. */ + temp = simplify_gen_binary (MINUS, Pmode, size, rounded_size); + if (temp != const0_rtx) + { + /* Manual CSE if the difference is not known at compile-time. */ + if (GET_CODE (temp) != CONST_INT) + temp = gen_rtx_MINUS (Pmode, size, rounded_size_op); + anti_adjust_stack (temp); + emit_stack_probe (stack_pointer_rtx); + } + } + + /* Adjust back to account for the additional first interval. */ + adjust_stack (GEN_INT (PROBE_INTERVAL + dope)); +} + /* Return an rtx representing the register or memory location in which a scalar value of data type VALTYPE was returned by a function call to function FUNC. diff --git a/gcc/expmed.c b/gcc/expmed.c index 98a99a2b5f1..8a5cf5054e7 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -5089,10 +5089,11 @@ make_tree (tree type, rtx x) default: t = build_decl (RTL_LOCATION (x), VAR_DECL, NULL_TREE, type); - /* If TYPE is a POINTER_TYPE, X might be Pmode with TYPE_MODE being - ptr_mode. So convert. */ + /* If TYPE is a POINTER_TYPE, we might need to convert X from + address mode to pointer mode. */ if (POINTER_TYPE_P (type)) - x = convert_memory_address (TYPE_MODE (type), x); + x = convert_memory_address_addr_space + (TYPE_MODE (type), x, TYPE_ADDR_SPACE (TREE_TYPE (type))); /* Note that we do *not* use SET_DECL_RTL here, because we do not want set_decl_rtl to go adjusting REG_ATTRS for this temporary. */ @@ -5497,9 +5498,13 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ)) || (! HONOR_SNANS (mode) && (code == EQ || code == NE)))) { + int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1) + || (STORE_FLAG_VALUE == -1 && normalizep == 1)); + /* For the reverse comparison, use either an addition or a XOR. */ - if ((STORE_FLAG_VALUE == 1 && normalizep == -1) - || (STORE_FLAG_VALUE == -1 && normalizep == 1)) + if (want_add + && rtx_cost (GEN_INT (normalizep), PLUS, + optimize_insn_for_speed_p ()) == 0) { tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0, STORE_FLAG_VALUE, target_mode); @@ -5508,7 +5513,9 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, GEN_INT (normalizep), target, 0, OPTAB_WIDEN); } - else + else if (!want_add + && rtx_cost (trueval, XOR, + optimize_insn_for_speed_p ()) == 0) { tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0, normalizep, target_mode); @@ -5595,9 +5602,13 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, && GET_MODE_SIZE (mode) < UNITS_PER_WORD && op1 == const0_rtx)) { + int want_add = ((STORE_FLAG_VALUE == 1 && normalizep == -1) + || (STORE_FLAG_VALUE == -1 && normalizep == 1)); + /* Again, for the reverse comparison, use either an addition or a XOR. */ - if ((STORE_FLAG_VALUE == 1 && normalizep == -1) - || (STORE_FLAG_VALUE == -1 && normalizep == 1)) + if (want_add + && rtx_cost (GEN_INT (normalizep), PLUS, + optimize_insn_for_speed_p ()) == 0) { tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0, STORE_FLAG_VALUE, target_mode); @@ -5605,7 +5616,9 @@ emit_store_flag (rtx target, enum rtx_code code, rtx op0, rtx op1, tem = expand_binop (target_mode, add_optab, tem, GEN_INT (normalizep), target, 0, OPTAB_WIDEN); } - else + else if (!want_add + && rtx_cost (trueval, XOR, + optimize_insn_for_speed_p ()) == 0) { tem = emit_store_flag_1 (subtarget, rcode, op0, op1, mode, 0, normalizep, target_mode); diff --git a/gcc/expr.c b/gcc/expr.c index 5d18435a99a..e62b5302114 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -877,6 +877,8 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, unsigned int align, int endp) { struct move_by_pieces_d data; + enum machine_mode to_addr_mode, from_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (from)); rtx to_addr, from_addr = XEXP (from, 0); unsigned int max_size = MOVE_MAX_PIECES + 1; enum machine_mode mode = VOIDmode, tmode; @@ -888,6 +890,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, data.from_addr = from_addr; if (to) { + to_addr_mode = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to)); to_addr = XEXP (to, 0); data.to = to; data.autinc_to @@ -898,6 +901,7 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, } else { + to_addr_mode = VOIDmode; to_addr = NULL_RTX; data.to = NULL_RTX; data.autinc_to = 1; @@ -933,32 +937,34 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, if (USE_LOAD_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_from) { - data.from_addr = copy_addr_to_reg (plus_constant (from_addr, len)); + data.from_addr = copy_to_mode_reg (from_addr_mode, + plus_constant (from_addr, len)); data.autinc_from = 1; data.explicit_inc_from = -1; } if (USE_LOAD_POST_INCREMENT (mode) && ! data.autinc_from) { - data.from_addr = copy_addr_to_reg (from_addr); + data.from_addr = copy_to_mode_reg (from_addr_mode, from_addr); data.autinc_from = 1; data.explicit_inc_from = 1; } if (!data.autinc_from && CONSTANT_P (from_addr)) - data.from_addr = copy_addr_to_reg (from_addr); + data.from_addr = copy_to_mode_reg (from_addr_mode, from_addr); if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to) { - data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); + data.to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (to_addr, len)); data.autinc_to = 1; data.explicit_inc_to = -1; } if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse && ! data.autinc_to) { - data.to_addr = copy_addr_to_reg (to_addr); + data.to_addr = copy_to_mode_reg (to_addr_mode, to_addr); data.autinc_to = 1; data.explicit_inc_to = 1; } if (!data.autinc_to && CONSTANT_P (to_addr)) - data.to_addr = copy_addr_to_reg (to_addr); + data.to_addr = copy_to_mode_reg (to_addr_mode, to_addr); } tmode = mode_for_size (MOVE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1); @@ -1013,7 +1019,8 @@ move_by_pieces (rtx to, rtx from, unsigned HOST_WIDE_INT len, if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0) emit_insn (gen_add2_insn (data.to_addr, constm1_rtx)); else - data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr, + data.to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (data.to_addr, -1)); } to1 = adjust_automodify_address (data.to, QImode, data.to_addr, @@ -1215,7 +1222,9 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, else if (emit_block_move_via_movmem (x, y, size, align, expected_align, expected_size)) ; - else if (may_use_call) + else if (may_use_call + && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)) + && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (y))) retval = emit_block_move_via_libcall (x, y, size, method == BLOCK_OP_TAILCALL); else @@ -1466,6 +1475,10 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, unsigned int align ATTRIBUTE_UNUSED) { rtx cmp_label, top_label, iter, x_addr, y_addr, tmp; + enum machine_mode x_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (x)); + enum machine_mode y_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (y)); enum machine_mode iter_mode; iter_mode = GET_MODE (size); @@ -1485,9 +1498,13 @@ emit_block_move_via_loop (rtx x, rtx y, rtx size, emit_jump (cmp_label); emit_label (top_label); - tmp = convert_modes (Pmode, iter_mode, iter, true); - x_addr = gen_rtx_PLUS (Pmode, x_addr, tmp); - y_addr = gen_rtx_PLUS (Pmode, y_addr, tmp); + tmp = convert_modes (x_addr_mode, iter_mode, iter, true); + x_addr = gen_rtx_PLUS (x_addr_mode, x_addr, tmp); + + if (x_addr_mode != y_addr_mode) + tmp = convert_modes (y_addr_mode, iter_mode, iter, true); + y_addr = gen_rtx_PLUS (y_addr_mode, y_addr, tmp); + x = change_address (x, QImode, x_addr); y = change_address (y, QImode, y_addr); @@ -2382,6 +2399,8 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len, rtx (*constfun) (void *, HOST_WIDE_INT, enum machine_mode), void *constfundata, unsigned int align, bool memsetp, int endp) { + enum machine_mode to_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to)); struct store_by_pieces_d data; if (len == 0) @@ -2410,7 +2429,8 @@ store_by_pieces (rtx to, unsigned HOST_WIDE_INT len, if (HAVE_POST_INCREMENT && data.explicit_inc_to > 0) emit_insn (gen_add2_insn (data.to_addr, constm1_rtx)); else - data.to_addr = copy_addr_to_reg (plus_constant (data.to_addr, + data.to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (data.to_addr, -1)); } to1 = adjust_automodify_address (data.to, QImode, data.to_addr, @@ -2465,6 +2485,8 @@ static void store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, unsigned int align ATTRIBUTE_UNUSED) { + enum machine_mode to_addr_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (data->to)); rtx to_addr = XEXP (data->to, 0); unsigned int max_size = STORE_MAX_PIECES + 1; enum machine_mode mode = VOIDmode, tmode; @@ -2496,7 +2518,8 @@ store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to) { - data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len)); + data->to_addr = copy_to_mode_reg (to_addr_mode, + plus_constant (to_addr, data->len)); data->autinc_to = 1; data->explicit_inc_to = -1; } @@ -2504,13 +2527,13 @@ store_by_pieces_1 (struct store_by_pieces_d *data ATTRIBUTE_UNUSED, if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse && ! data->autinc_to) { - data->to_addr = copy_addr_to_reg (to_addr); + data->to_addr = copy_to_mode_reg (to_addr_mode, to_addr); data->autinc_to = 1; data->explicit_inc_to = 1; } if ( !data->autinc_to && CONSTANT_P (to_addr)) - data->to_addr = copy_addr_to_reg (to_addr); + data->to_addr = copy_to_mode_reg (to_addr_mode, to_addr); } tmode = mode_for_size (STORE_MAX_PIECES * BITS_PER_UNIT, MODE_INT, 1); @@ -2641,9 +2664,11 @@ clear_storage_hints (rtx object, rtx size, enum block_op_methods method, else if (set_storage_via_setmem (object, size, const0_rtx, align, expected_align, expected_size)) ; - else + else if (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (object))) return set_storage_via_libcall (object, size, const0_rtx, method == BLOCK_OP_TAILCALL); + else + gcc_unreachable (); return NULL; } @@ -3432,12 +3457,14 @@ emit_move_insn (rtx x, rtx y) /* If X or Y are memory references, verify that their addresses are valid for the machine. */ if (MEM_P (x) - && (! memory_address_p (GET_MODE (x), XEXP (x, 0)) + && (! memory_address_addr_space_p (GET_MODE (x), XEXP (x, 0), + MEM_ADDR_SPACE (x)) && ! push_operand (x, GET_MODE (x)))) x = validize_mem (x); if (MEM_P (y) - && ! memory_address_p (GET_MODE (y), XEXP (y, 0))) + && ! memory_address_addr_space_p (GET_MODE (y), XEXP (y, 0), + MEM_ADDR_SPACE (y))) y = validize_mem (y); gcc_assert (mode != BLKmode); @@ -4208,6 +4235,7 @@ expand_assignment (tree to, tree from, bool nontemporal) if (offset != 0) { + enum machine_mode address_mode; rtx offset_rtx; if (!MEM_P (to_rtx)) @@ -4220,13 +4248,10 @@ expand_assignment (tree to, tree from, bool nontemporal) } offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); -#else - if (GET_MODE (offset_rtx) != ptr_mode) - offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); -#endif + address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx)); + if (GET_MODE (offset_rtx) != address_mode) + offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); /* A constant address in TO_RTX can have VOIDmode, we must not try to call force_reg for that case. Avoid that case. */ @@ -4298,20 +4323,25 @@ expand_assignment (tree to, tree from, bool nontemporal) else if (TREE_CODE (to) == MISALIGNED_INDIRECT_REF) { + addr_space_t as = ADDR_SPACE_GENERIC; enum machine_mode mode, op_mode1; enum insn_code icode; rtx reg, addr, mem, insn; + if (POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (to, 0)))) + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (to, 0)))); + reg = expand_expr (from, NULL_RTX, VOIDmode, EXPAND_NORMAL); reg = force_not_mem (reg); mode = TYPE_MODE (TREE_TYPE (to)); addr = expand_expr (TREE_OPERAND (to, 0), NULL_RTX, VOIDmode, EXPAND_SUM); - addr = memory_address (mode, addr); + addr = memory_address_addr_space (mode, addr, as); mem = gen_rtx_MEM (mode, addr); set_mem_attributes (mem, to, 0); + set_mem_addr_space (mem, as); icode = movmisalign_optab->handlers[mode].insn_code; gcc_assert (icode != CODE_FOR_nothing); @@ -4360,7 +4390,10 @@ expand_assignment (tree to, tree from, bool nontemporal) else { if (POINTER_TYPE_P (TREE_TYPE (to))) - value = convert_memory_address (GET_MODE (to_rtx), value); + value = convert_memory_address_addr_space + (GET_MODE (to_rtx), value, + TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (to)))); + emit_move_insn (to_rtx, value); } preserve_temp_slots (to_rtx); @@ -4400,6 +4433,8 @@ expand_assignment (tree to, tree from, bool nontemporal) the place the value is being stored, use a safe function when copying a value through a pointer into a structure value return block. */ if (TREE_CODE (to) == RESULT_DECL && TREE_CODE (from) == INDIRECT_REF + && ADDR_SPACE_GENERIC_P + (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (TREE_OPERAND (from, 0))))) && cfun->returns_struct && !cfun->returns_pcc_struct) { @@ -4718,6 +4753,11 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); else { + enum machine_mode pointer_mode + = targetm.addr_space.pointer_mode (MEM_ADDR_SPACE (target)); + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (target)); + /* Compute the size of the data to copy from the string. */ tree copy_size = size_binop_loc (loc, MIN_EXPR, @@ -4730,14 +4770,14 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) rtx label = 0; /* Copy that much. */ - copy_size_rtx = convert_to_mode (ptr_mode, copy_size_rtx, + copy_size_rtx = convert_to_mode (pointer_mode, copy_size_rtx, TYPE_UNSIGNED (sizetype)); emit_block_move (target, temp, copy_size_rtx, (call_param_p ? BLOCK_OP_CALL_PARM : BLOCK_OP_NORMAL)); /* Figure out how much is left in TARGET that we have to clear. - Do all calculations in ptr_mode. */ + Do all calculations in pointer_mode. */ if (CONST_INT_P (copy_size_rtx)) { size = plus_constant (size, -INTVAL (copy_size_rtx)); @@ -4750,11 +4790,10 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) copy_size_rtx, NULL_RTX, 0, OPTAB_LIB_WIDEN); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (copy_size_rtx) != Pmode) - copy_size_rtx = convert_to_mode (Pmode, copy_size_rtx, + if (GET_MODE (copy_size_rtx) != address_mode) + copy_size_rtx = convert_to_mode (address_mode, + copy_size_rtx, TYPE_UNSIGNED (sizetype)); -#endif target = offset_address (target, copy_size_rtx, highest_pow2_factor (copy_size)); @@ -5244,6 +5283,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) if (offset) { + enum machine_mode address_mode; rtx offset_rtx; offset @@ -5254,13 +5294,10 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) offset_rtx = expand_normal (offset); gcc_assert (MEM_P (to_rtx)); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); -#else - if (GET_MODE (offset_rtx) != ptr_mode) - offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); -#endif + address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (to_rtx)); + if (GET_MODE (offset_rtx) != address_mode) + offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); to_rtx = offset_address (to_rtx, offset_rtx, highest_pow2_factor (offset)); @@ -6783,7 +6820,7 @@ expand_expr_constant (tree exp, int defer, enum expand_modifier modifier) static rtx expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, - enum expand_modifier modifier) + enum expand_modifier modifier, addr_space_t as) { rtx result, subtarget; tree inner, offset; @@ -6810,7 +6847,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, case CONST_DECL: /* Recurse and make the output_constant_def clause above handle this. */ return expand_expr_addr_expr_1 (DECL_INITIAL (exp), target, - tmode, modifier); + tmode, modifier, as); case REALPART_EXPR: /* The real part of the complex number is always first, therefore @@ -6900,7 +6937,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, TYPE_ALIGN (TREE_TYPE (inner)) = TYPE_ALIGN (TREE_TYPE (exp)); TYPE_USER_ALIGN (TREE_TYPE (inner)) = 1; } - result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier); + result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier, as); if (offset) { @@ -6912,8 +6949,8 @@ expand_expr_addr_expr_1 (tree exp, rtx target, enum machine_mode tmode, modifier == EXPAND_INITIALIZER ? EXPAND_INITIALIZER : EXPAND_NORMAL); - result = convert_memory_address (tmode, result); - tmp = convert_memory_address (tmode, tmp); + result = convert_memory_address_addr_space (tmode, result, as); + tmp = convert_memory_address_addr_space (tmode, tmp, as); if (modifier == EXPAND_SUM || modifier == EXPAND_INITIALIZER) result = gen_rtx_PLUS (tmode, result, tmp); @@ -6946,6 +6983,9 @@ static rtx expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode, enum expand_modifier modifier) { + addr_space_t as = ADDR_SPACE_GENERIC; + enum machine_mode address_mode = Pmode; + enum machine_mode pointer_mode = ptr_mode; enum machine_mode rmode; rtx result; @@ -6953,14 +6993,21 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode, if (tmode == VOIDmode) tmode = TYPE_MODE (TREE_TYPE (exp)); + if (POINTER_TYPE_P (TREE_TYPE (exp))) + { + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp))); + address_mode = targetm.addr_space.address_mode (as); + pointer_mode = targetm.addr_space.pointer_mode (as); + } + /* We can get called with some Weird Things if the user does silliness like "(short) &a". In that case, convert_memory_address won't do the right thing, so ignore the given target mode. */ - if (tmode != Pmode && tmode != ptr_mode) - tmode = Pmode; + if (tmode != address_mode && tmode != pointer_mode) + tmode = address_mode; result = expand_expr_addr_expr_1 (TREE_OPERAND (exp, 0), target, - tmode, modifier); + tmode, modifier, as); /* Despite expand_expr claims concerning ignoring TMODE when not strictly convenient, stuff breaks if we don't honor it. Note @@ -6969,7 +7016,7 @@ expand_expr_addr_expr (tree exp, rtx target, enum machine_mode tmode, if (rmode == VOIDmode) rmode = tmode; if (rmode != tmode) - result = convert_memory_address (tmode, result); + result = convert_memory_address_addr_space (tmode, result, as); return result; } @@ -7343,6 +7390,39 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, return REDUCE_BIT_FIELD (op0); + case ADDR_SPACE_CONVERT_EXPR: + { + tree treeop0_type = TREE_TYPE (treeop0); + addr_space_t as_to; + addr_space_t as_from; + + gcc_assert (POINTER_TYPE_P (type)); + gcc_assert (POINTER_TYPE_P (treeop0_type)); + + as_to = TYPE_ADDR_SPACE (TREE_TYPE (type)); + as_from = TYPE_ADDR_SPACE (TREE_TYPE (treeop0_type)); + + /* Conversions between pointers to the same address space should + have been implemented via CONVERT_EXPR / NOP_EXPR. */ + gcc_assert (as_to != as_from); + + /* Ask target code to handle conversion between pointers + to overlapping address spaces. */ + if (targetm.addr_space.subset_p (as_to, as_from) + || targetm.addr_space.subset_p (as_from, as_to)) + { + op0 = expand_expr (treeop0, NULL_RTX, VOIDmode, modifier); + op0 = targetm.addr_space.convert (op0, treeop0_type, type); + gcc_assert (op0); + return op0; + } + + /* For disjoint address spaces, converting anything but + a null pointer invokes undefined behaviour. We simply + always return a null pointer here. */ + return CONST0_RTX (mode); + } + case POINTER_PLUS_EXPR: /* Even though the sizetype mode and the pointer's mode can be different expand is able to handle this correctly and get the correct result out @@ -8431,7 +8511,9 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, decl_rtl = use_anchored_address (decl_rtl); if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_SUM - && !memory_address_p (DECL_MODE (exp), XEXP (decl_rtl, 0))) + && !memory_address_addr_space_p (DECL_MODE (exp), + XEXP (decl_rtl, 0), + MEM_ADDR_SPACE (decl_rtl))) temp = replace_equiv_address (decl_rtl, copy_rtx (XEXP (decl_rtl, 0))); } @@ -8551,7 +8633,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (modifier != EXPAND_CONST_ADDRESS && modifier != EXPAND_INITIALIZER && modifier != EXPAND_SUM - && ! memory_address_p (mode, XEXP (temp, 0))) + && ! memory_address_addr_space_p (mode, XEXP (temp, 0), + MEM_ADDR_SPACE (temp))) return replace_equiv_address (temp, copy_rtx (XEXP (temp, 0))); return temp; @@ -8607,6 +8690,8 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case INDIRECT_REF: { tree exp1 = treeop0; + addr_space_t as = ADDR_SPACE_GENERIC; + enum machine_mode address_mode = Pmode; if (modifier != EXPAND_WRITE) { @@ -8617,19 +8702,26 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, return expand_expr (t, target, tmode, modifier); } + if (POINTER_TYPE_P (TREE_TYPE (exp1))) + { + as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp1))); + address_mode = targetm.addr_space.address_mode (as); + } + op0 = expand_expr (exp1, NULL_RTX, VOIDmode, EXPAND_SUM); - op0 = memory_address (mode, op0); + op0 = memory_address_addr_space (mode, op0, as); if (code == ALIGN_INDIRECT_REF) { int align = TYPE_ALIGN_UNIT (type); - op0 = gen_rtx_AND (Pmode, op0, GEN_INT (-align)); - op0 = memory_address (mode, op0); + op0 = gen_rtx_AND (address_mode, op0, GEN_INT (-align)); + op0 = memory_address_addr_space (mode, op0, as); } temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, exp, 0); + set_mem_addr_space (temp, as); /* Resolve the misalignment now, so that we don't have to remember to resolve it later. Of course, this only works for reads. */ @@ -8661,13 +8753,15 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, case TARGET_MEM_REF: { + addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (exp)); struct mem_address addr; get_address_description (exp, &addr); - op0 = addr_for_mem_ref (&addr, true); - op0 = memory_address (mode, op0); + op0 = addr_for_mem_ref (&addr, as, true); + op0 = memory_address_addr_space (mode, op0, as); temp = gen_rtx_MEM (mode, op0); set_mem_attributes (temp, TMR_ORIGINAL (exp), 0); + set_mem_addr_space (temp, as); } return temp; @@ -8955,18 +9049,16 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, if (offset) { + enum machine_mode address_mode; rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); gcc_assert (MEM_P (op0)); -#ifdef POINTERS_EXTEND_UNSIGNED - if (GET_MODE (offset_rtx) != Pmode) - offset_rtx = convert_to_mode (Pmode, offset_rtx, 0); -#else - if (GET_MODE (offset_rtx) != ptr_mode) - offset_rtx = convert_to_mode (ptr_mode, offset_rtx, 0); -#endif + address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (op0)); + if (GET_MODE (offset_rtx) != address_mode) + offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); if (GET_MODE (op0) == BLKmode /* A constant address in OP0 can have VOIDmode, we must diff --git a/gcc/expr.h b/gcc/expr.h index 4e02c24b75f..e84779639b5 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -218,9 +218,9 @@ do { \ #define STACK_CHECK_STATIC_BUILTIN 0 #endif -/* The default interval is one page. */ -#ifndef STACK_CHECK_PROBE_INTERVAL -#define STACK_CHECK_PROBE_INTERVAL 4096 +/* The default interval is one page (4096 bytes). */ +#ifndef STACK_CHECK_PROBE_INTERVAL_EXP +#define STACK_CHECK_PROBE_INTERVAL_EXP 12 #endif /* The default is to do a store into the stack. */ @@ -228,6 +228,11 @@ do { \ #define STACK_CHECK_PROBE_LOAD 0 #endif +/* The default is not to move the stack pointer. */ +#ifndef STACK_CHECK_MOVING_SP +#define STACK_CHECK_MOVING_SP 0 +#endif + /* This is a kludge to try to capture the discrepancy between the old mechanism (generic stack checking) and the new mechanism (static builtin stack checking). STACK_CHECK_PROTECT needs to be bumped @@ -252,7 +257,7 @@ do { \ one probe per function. */ #ifndef STACK_CHECK_MAX_FRAME_SIZE #define STACK_CHECK_MAX_FRAME_SIZE \ - (STACK_CHECK_PROBE_INTERVAL - UNITS_PER_WORD) + ((1 << STACK_CHECK_PROBE_INTERVAL_EXP) - UNITS_PER_WORD) #endif /* This is arbitrary, but should be large enough everywhere. */ @@ -650,9 +655,15 @@ extern rtx force_label_rtx (tree); The constant terms are added and stored via a second arg. */ extern rtx eliminate_constant_term (rtx, rtx *); -/* Convert arg to a valid memory address for specified machine mode, - by emitting insns to perform arithmetic if nec. */ -extern rtx memory_address (enum machine_mode, rtx); +/* Convert arg to a valid memory address for specified machine mode that points + to a specific named address space, by emitting insns to perform arithmetic + if necessary. */ +extern rtx memory_address_addr_space (enum machine_mode, rtx, addr_space_t); + +/* Like memory_address_addr_space, except assume the memory address points to + the generic named address space. */ +#define memory_address(MODE,RTX) \ + memory_address_addr_space ((MODE), (RTX), ADDR_SPACE_GENERIC) /* Return a memory reference like MEMREF, but with its mode changed to MODE and its address changed to ADDR. @@ -773,10 +784,9 @@ extern void update_nonlocal_goto_save_area (void); extern rtx allocate_dynamic_stack_space (rtx, rtx, int); /* Probe a range of stack addresses from FIRST to FIRST+SIZE, inclusive. - FIRST is a constant and size is a Pmode RTX. These are offsets from the - current stack pointer. STACK_GROWS_DOWNWARD says whether to add or - subtract from the stack. If SIZE is constant, this is done - with a fixed number of probes. Otherwise, we must make a loop. */ + FIRST is a constant and size is a Pmode RTX. These are offsets from + the current stack pointer. STACK_GROWS_DOWNWARD says whether to add + or subtract them from the stack pointer. */ extern void probe_stack_range (HOST_WIDE_INT, rtx); /* Return an rtx that refers to the value returned by a library call diff --git a/gcc/final.c b/gcc/final.c index 78a698b4484..ef450d2fe3e 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -204,10 +204,8 @@ rtx final_sequence; static int dialect_number; #endif -#ifdef HAVE_conditional_execution /* Nonnull if the insn currently being emitted was a COND_EXEC pattern. */ rtx current_insn_predicate; -#endif #ifdef HAVE_ATTR_length static int asm_insn_count (rtx); @@ -1399,13 +1397,23 @@ static int asm_insn_count (rtx body) { const char *templ; - int count = 1; if (GET_CODE (body) == ASM_INPUT) templ = XSTR (body, 0); else templ = decode_asm_operands (body, NULL, NULL, NULL, NULL, NULL); + return asm_str_count (templ); +} +#endif + +/* Return the number of machine instructions likely to be generated for the + inline-asm template. */ +int +asm_str_count (const char *templ) +{ + int count = 1; + if (!*templ) return 0; @@ -1416,7 +1424,6 @@ asm_insn_count (rtx body) return count; } -#endif /* ??? This is probably the wrong place for these. */ /* Structure recording the mapping from source file and directory @@ -2093,10 +2100,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, const char *templ; bool is_stmt; -#ifdef HAVE_conditional_execution /* Reset this early so it is correct for ASM statements. */ current_insn_predicate = NULL_RTX; -#endif + /* An INSN, JUMP_INSN or CALL_INSN. First check for special kinds that recog doesn't recognize. */ @@ -2581,10 +2587,9 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, FINAL_PRESCAN_INSN (insn, recog_data.operand, recog_data.n_operands); #endif -#ifdef HAVE_conditional_execution - if (GET_CODE (PATTERN (insn)) == COND_EXEC) + if (targetm.have_conditional_execution () + && GET_CODE (PATTERN (insn)) == COND_EXEC) current_insn_predicate = COND_EXEC_TEST (PATTERN (insn)); -#endif #ifdef HAVE_cc0 cc_prev_status = cc_status; @@ -2675,6 +2680,26 @@ final_scan_insn (rtx insn, FILE *file, int optimize ATTRIBUTE_UNUSED, /* Output assembler code from the template. */ output_asm_insn (templ, recog_data.operand); + /* Record point-of-call information for ICF debugging. */ + if (flag_enable_icf_debug && CALL_P (insn)) + { + rtx x = call_from_call_insn (insn); + x = XEXP (x, 0); + if (x && MEM_P (x)) + { + if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF) + { + tree t; + x = XEXP (x, 0); + t = SYMBOL_REF_DECL (x); + if (t) + (*debug_hooks->direct_call) (t); + } + else + (*debug_hooks->virtual_call) (INSN_UID (insn)); + } + } + /* Some target machines need to postscan each insn after it is output. */ if (targetm.asm_out.final_postscan_insn) diff --git a/gcc/flags.h b/gcc/flags.h index 8b71302f3e4..bd8b82d4372 100644 --- a/gcc/flags.h +++ b/gcc/flags.h @@ -111,6 +111,17 @@ extern int optimize; extern int optimize_size; +/* True if this is the LTO front end (lto1). This is used to disable + gimple generation and lowering passes that are normally run on the + output of a front end. These passes must be bypassed for lto since + they have already been done before the gimple was written. */ + +extern bool in_lto_p; + +/* Nonzero if we should write GIMPLE bytecode for link-time optimization. */ + +extern int flag_generate_lto; + /* Used to set the level of -Wstrict-aliasing, when no level is specified. The external way to set the default level is to use -Wstrict-aliasing=level. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 1539ad21387..3403938edc3 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -206,15 +206,9 @@ fit_double_type (unsigned HOST_WIDE_INT l1, HOST_WIDE_INT h1, { unsigned HOST_WIDE_INT low0 = l1; HOST_WIDE_INT high0 = h1; - unsigned int prec; + unsigned int prec = int_or_pointer_precision (type); int sign_extended_type; - if (POINTER_TYPE_P (type) - || TREE_CODE (type) == OFFSET_TYPE) - prec = POINTER_SIZE; - else - prec = TYPE_PRECISION (type); - /* Size types *are* sign extended. */ sign_extended_type = (!TYPE_UNSIGNED (type) || (TREE_CODE (type) == INTEGER_TYPE @@ -2647,8 +2641,16 @@ fold_convert_loc (location_t loc, tree type, tree arg) switch (TREE_CODE (type)) { + case POINTER_TYPE: + case REFERENCE_TYPE: + /* Handle conversions between pointers to different address spaces. */ + if (POINTER_TYPE_P (orig) + && (TYPE_ADDR_SPACE (TREE_TYPE (type)) + != TYPE_ADDR_SPACE (TREE_TYPE (orig)))) + return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, arg); + /* fall through */ + case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE: - case POINTER_TYPE: case REFERENCE_TYPE: case OFFSET_TYPE: if (TREE_CODE (arg) == INTEGER_CST) { @@ -3179,6 +3181,12 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags) || POINTER_TYPE_P (TREE_TYPE (arg0)) != POINTER_TYPE_P (TREE_TYPE (arg1))) return 0; + /* We cannot consider pointers to different address space equal. */ + if (POINTER_TYPE_P (TREE_TYPE (arg0)) && POINTER_TYPE_P (TREE_TYPE (arg1)) + && (TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg0))) + != TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (arg1))))) + return 0; + /* If both types don't have the same precision, then it is not safe to strip NOPs. */ if (TYPE_PRECISION (TREE_TYPE (arg0)) != TYPE_PRECISION (TREE_TYPE (arg1))) @@ -8682,6 +8690,11 @@ fold_unary_loc (location_t loc, enum tree_code code, tree type, tree op0) tem = fold_convert_const (code, type, op0); return tem ? tem : NULL_TREE; + case ADDR_SPACE_CONVERT_EXPR: + if (integer_zerop (arg0)) + return fold_convert_const (code, type, arg0); + return NULL_TREE; + case FIXED_CONVERT_EXPR: tem = fold_convert_const (code, type, arg0); return tem ? tem : NULL_TREE; @@ -10134,7 +10147,6 @@ fold_binary_loc (location_t loc, tem = fold_build2_loc (loc, code, type, fold_convert_loc (loc, TREE_TYPE (op0), TREE_OPERAND (arg0, 1)), op1); - protected_set_expr_location (tem, loc); tem = build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg0, 0), tem); goto fold_binary_exit; } @@ -10144,7 +10156,6 @@ fold_binary_loc (location_t loc, tem = fold_build2_loc (loc, code, type, op0, fold_convert_loc (loc, TREE_TYPE (op1), TREE_OPERAND (arg1, 1))); - protected_set_expr_location (tem, loc); tem = build2 (COMPOUND_EXPR, type, TREE_OPERAND (arg1, 0), tem); goto fold_binary_exit; } diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index c325d258ae8..eef8cf8d5a0 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,349 @@ +2009-11-05 Steven G. Kargl + + PR fortran/41918 + * fortran/trans-decl.c: Silence intent(out) warning for derived type + dummy arguments with default initialization. + +2009-11-05 Janus Weil + + PR fortran/41556 + * interface.c (matching_typebound_op,gfc_extend_assign): Handle CLASS + variables. + +2009-11-05 Janus Weil + + PR fortran/41556 + PR fortran/41873 + * resolve.c (resolve_function,resolve_call): Prevent abstract interfaces + from being called, but allow deferred type-bound procedures with + abstract interface. + +2009-11-04 Tobias Burnus + Janus Weil + + PR fortran/41556 + PR fortran/41937 + * interface.c (gfc_check_operator_interface): Handle CLASS arguments. + * resolve.c (resolve_allocate_expr): Handle allocatable components of + CLASS variables. + +2009-11-04 Richard Guenther + + * options.c (gfc_post_options): Rely on common code processing + LTO options. Only enable -fwhole-file here. + +2009-11-03 Tobias Burnus + + PR fortran/41907 + * trans-expr.c (gfc_conv_procedure_call): Fix presence check + for optional arguments. + +2009-11-01 Tobias Burnus + + PR fortran/41872 + * trans-decl.c (gfc_trans_deferred_vars): Do not nullify + autodeallocated allocatable scalars at the end of scope. + (gfc_generate_function_code): Fix indention. + * trans-expr.c (gfc_conv_procedure_call): For allocatable + scalars, fix calling by reference and autodeallocating + of intent out variables. + +2009-11-01 Tobias Burnus + + PR fortran/41850 + * trans-expr.c (gfc_conv_procedure_call): Deallocate intent-out + variables only when present. Remove unneccessary present check. + +2009-10-29 Tobias Burnus + + PR fortran/41777 + * trans-expr.c (gfc_conv_procedure_call,gfc_conv_expr_reference): + Use for generic EXPR_FUNCTION the attributes of the specific + function. + +2009-10-29 Janne Blomqvist + + PR fortran/41860 + * resolve.c (apply_default_init_local): Treat -fno-automatic as if + var was saved. + +2009-10-28 Rafael Avila de Espindola + + * trans-common.c (create_common): Set TREE_PUBLIC to false on + fake variables. + +2009-10-26 Janus Weil + + PR fortran/41714 + * trans.c (gfc_trans_code): Remove call to + 'tree_annotate_all_with_location'. Location should already be set. + * trans-openmp.c (gfc_trans_omp_workshare): Ditto. + * trans-stmt.c (gfc_trans_allocate): Do correct data initialization for + CLASS variables with SOURCE tag, plus some cleanup. + +2009-10-24 Janus Weil + Paul Thomas + + PR fortran/41784 + * module.c (load_derived_extensions): Skip symbols which are not being + loaded. + +2009-10-24 Paul Thomas + + PR fortran/41772 + * trans-intrinsic.c (gfc_conv_intrinsic_transfer): Stop'extent' + from going negative. + +2009-10-23 Janus Weil + + PR fortran/41800 + * trans-expr.c (gfc_trans_scalar_assign): Handle CLASS variables. + +2009-10-23 Janus Weil + + PR fortran/41758 + * match.c (conformable_arrays): Move to resolve.c. + (gfc_match_allocate): Don't resolve SOURCE expr yet, and move some + checks to resolve_allocate_expr. + * resolve.c (conformable_arrays): Moved here from match.c. + (resolve_allocate_expr): Moved some checks here from gfc_match_allocate. + (resolve_code): Resolve SOURCE tag for ALLOCATE expressions. + +2009-10-22 Janus Weil + + PR fortran/41781 + * resolve.c (resolve_codes): Don't clear 'cs_base' for BLOCK constructs, + to make sure labels are treated correctly. + * symbol.c (gfc_get_st_label): Create labels in the right namespace. + For BLOCK constructs go into the parent namespace. + +2009-10-21 Janus Weil + + PR fortran/41706 + PR fortran/41766 + * match.c (select_type_set_tmp): Set flavor for temporary. + * resolve.c (resolve_class_typebound_call): Correctly resolve actual + arguments. + +2009-10-20 Paul Thomas + + PR fortran/41706 + * resolve.c (resolve_arg_exprs): New function. + (resolve_class_compcall): Call the above. + (resolve_class_typebound_call): The same. + +2009-10-19 Janus Weil + + PR fortran/41586 + * parse.c (parse_derived): Correctly set 'alloc_comp' and 'pointer_comp' + for CLASS variables. + * trans-array.c (structure_alloc_comps): Handle deallocation and + nullification of allocatable scalar components. + * trans-decl.c (gfc_get_symbol_decl): Remember allocatable scalars for + automatic deallocation. + (gfc_trans_deferred_vars): Automatically deallocate allocatable scalars. + +2009-10-19 Tobias Burnus + Steven G. Kargl + + PR fortran/41755 + * symbol.c (gfc_undo_symbols): Add NULL check. + * match.c (gfc_match_equivalence): Add check for + missing comma. + +2009-10-19 Richard Guenther + + PR fortran/41494 + * trans-expr.c (gfc_trans_scalar_assign): Do not call + gfc_evaluate_now. + +2009-10-17 Janus Weil + Paul Thomas + + PR fortran/41608 + * decl.c (gfc_match_data_decl): Add BT_CLASS for undefined type + and empty type errors. + * parse.c (gfc_build_block_ns): Only set recursive if parent ns + has a proc_name. + + PR fortran/41629 + PR fortran/41618 + PR fortran/41587 + * gfortran.h : Add class_ok bitfield to symbol_attr. + * decl.c (build_sym): Set attr.class_ok if dummy, pointer or + allocatable. + (build_struct): Use gfc_try 't' to carry errors past the call + to encapsulate_class_symbol. + (attr_decl1): For a CLASS object, apply the new attribute to + the data component. + * match.c (gfc_match_select_type): Set attr.class_ok for an + assigned selector. + * resolve.c (resolve_fl_variable_derived): Check a CLASS object + is dummy, pointer or allocatable by testing the class_ok and + the use_assoc attribute. + +2009-10-16 Janus Weil + + PR fortran/41719 + * resolve.c (resolve_ordinary_assign): Reject intrinsic assignments + to polymorphic variables. + +2009-10-16 Paul Thomas + + PR fortran/41648 + PR fortran/41656 + * trans-expr.c (select_class_proc): Convert the expression for the + vindex, carried on the first member of the esym list. + * gfortran.h : Add the vindex field to the esym_list structure. + and eliminate the class_object field. + * resolve.c (check_class_members): Remove the setting of the + class_object field. + (vindex_expr): New function. + (get_class_from_expr): New function. + (resolve_class_compcall): Call the above to find the ultimate + class or derived component. If derived, do not generate the + esym list. Add and expression for the vindex to the esym list + by calling the above. + (resolve_class_typebound_call): The same. + +2009-10-15 Steven G. Kargl + + PR fortran/41712 + * intrinsic.texi: Explicitly state that ETIME and DTIME take + REAL(4) arguments. Fix nearby typographically errors where + /leq was used instead of \leq. + +2009-10-13 Janus Weil + + PR fortran/41581 + * decl.c (encapsulate_class_symbol): Add new component '$size'. + * resolve.c (resolve_allocate_expr): Move CLASS handling to + gfc_trans_allocate. + (resolve_class_assign): Replaced by gfc_trans_class_assign. + (resolve_code): Remove calls to resolve_class_assign. + * trans.c (gfc_trans_code): Use new function gfc_trans_class_assign. + * trans-expr.c (get_proc_ptr_comp): Fix a memory leak. + (gfc_conv_procedure_call): For CLASS dummies, set the + $size component. + (gfc_trans_class_assign): New function, replacing resolve_class_assign. + * trans-stmt.h (gfc_trans_class_assign): New prototype. + * trans-stmt.c (gfc_trans_allocate): Use correct size when allocating + CLASS variables. Do proper initialization. Move some code here from + resolve_allocate_expr. + +2009-10-11 Jerry DeLisle + + PR fortran/38439 + * io.c (check_format): Fix locus for error messages and fix a comment. + +2009-10-11 Paul Thomas + + PR fortran/41583 + * decl.c (hash_value): New function. + (gfc_match_derived_decl): Call it. + +2009-10-09 Janus Weil + + PR fortran/41585 + * decl.c (build_struct): Bugfix for CLASS components. + +2009-10-09 Tobias Burnus + + PR fortran/41582 + * decl.c (encapsulate_class_symbol): Save attr.abstract. + * resolve.c (resolve_allocate_expr): Reject class allocate + without typespec or source=. + * trans-stmt.c (gfc_trans_allocate): Change gfc_warning + into gfc_error for "not yet implemented". + +2009-10-09 Janus Weil + + PR fortran/41579 + * gfortran.h (gfc_select_type_stack): New struct, to be used as a stack + for SELECT TYPE statements. + (select_type_stack): New global variable. + (type_selector,select_type_tmp): Removed. + * match.c (type_selector,type_selector): Removed. + (select_type_stack): New variable, serving as a stack for + SELECT TYPE statements. + (select_type_push,select_type_set_tmp): New functions. + (gfc_match_select_type): Call select_type_push. + (gfc_match_type_is): Call select_type_set_tmp. + * parse.c (select_type_pop): New function. + (parse_select_type_block): Call select_type_pop. + * symbol.c (select_type_insert_tmp): New function. + (gfc_find_sym_tree): Call select_type_insert_tmp. + +2009-10-07 Kaveh R. Ghazi + + * arith.c (arith_power): Use mpc_pow_z. + * gfortran.h (HAVE_mpc_pow_z): Define. + +2009-10-07 Daniel Kraft + + PR fortran/41615 + * resolve.c (resolve_contained_fntype): Clarify error message for + invalid assumed-length character result on module procedures. + +2009-10-07 Janus Weil + + * expr.c (gfc_check_pointer_assign): Do the correct type checking when + CLASS variables are involved. + * match.c (gfc_match_select_type): Parse associate-name in SELECT TYPE + statements, and set up a local namespace for the SELECT TYPE block. + * parse.h (gfc_build_block_ns): New prototype. + * parse.c (parse_select_type_block): Return from local namespace to its + parent after SELECT TYPE block. + (gfc_build_block_ns): New function for setting up the local namespace + for a BLOCK construct. + (parse_block_construct): Use gfc_build_block_ns. + * resolve.c (resolve_select_type): Insert assignment for the selector + variable, in case an associate-name is given, and put the SELECT TYPE + statement inside a BLOCK. + (resolve_code): Call resolve_class_assign after checking the assignment. + * symbol.c (gfc_find_sym_tree): Moved some code here from + gfc_get_ha_sym_tree. + (gfc_get_ha_sym_tree): Moved some code to gfc_find_sym_tree. + +2009-10-07 Paul Thomas + + PR fortran/41613 + * resolve.c (check_class_members): Reset compcall.assign. + +2009-10-05 Paul Thomas + + * trans-expr.c (select_class_proc): New function. + (conv_function_val): Deal with class methods and call above. + * symbol.c (gfc_type_compatible): Treat case where both ts1 and + ts2 are BT_CLASS. + gfortran.h : Add structure gfc_class_esym_list and include in + the structure gfc_expr. + * module.c (load_derived_extensions): New function. + (read_module): Call above. + (write_dt_extensions): New function. + (write_derived_extensions): New function. + (write_module): Use the above. + * resolve.c (resolve_typebound_call): Add a function expression + for class methods. This carries the chain of symbols for the + dynamic dispatch in select_class_proc. + (resolve_compcall): Add second, boolean argument to indicate if + a function is being handled. + (check_members): New function. + (check_class_members): New function. + (resolve_class_compcall): New function. + (resolve_class_typebound_call): New function. + (gfc_resolve_expr): Call above for component calls.. + +2009-10-05 Daniel Kraft + + PR fortran/41403 + * trans-stmt.c (gfc_trans_goto): Ignore statement list on assigned goto + if it is present. + +2009-10-03 Richard Guenther + + * options.c (gfc_post_options): Handle -flto and -fwhopr. + 2009-10-02 Tobias Burnus PR fortran/41479 @@ -285,7 +631,6 @@ * parse.c (next_free): Improve error locus printing. (next_fixed): Change gfc_warn to gfc_warning_now, and improve locus reporting. - 2009-09-16 Michael Matz diff --git a/gcc/fortran/arith.c b/gcc/fortran/arith.c index dddf7e003ce..82a43ad7178 100644 --- a/gcc/fortran/arith.c +++ b/gcc/fortran/arith.c @@ -1111,7 +1111,10 @@ arith_power (gfc_expr *op1, gfc_expr *op2, gfc_expr **resultp) case BT_COMPLEX: { -#ifdef HAVE_mpc_pow +#ifdef HAVE_mpc_pow_z + mpc_pow_z (result->value.complex, op1->value.complex, + op2->value.integer, GFC_MPC_RND_MODE); +#elif defined(HAVE_mpc_pow) mpc_t apower; gfc_set_model (mpc_realref (op1->value.complex)); mpc_init2 (apower, mpfr_get_default_prec()); diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c index 171eeaa97bf..9b6f8ea0a4f 100644 --- a/gcc/fortran/check.c +++ b/gcc/fortran/check.c @@ -599,10 +599,8 @@ gfc_check_associated (gfc_expr *pointer, gfc_expr *target) where = &pointer->where; - if (pointer->expr_type == EXPR_VARIABLE) - attr1 = gfc_variable_attr (pointer, NULL); - else if (pointer->expr_type == EXPR_FUNCTION) - attr1 = pointer->symtree->n.sym->attr; + if (pointer->expr_type == EXPR_VARIABLE || pointer->expr_type == EXPR_FUNCTION) + attr1 = gfc_expr_attr (pointer); else if (pointer->expr_type == EXPR_NULL) goto null_arg; else @@ -624,10 +622,8 @@ gfc_check_associated (gfc_expr *pointer, gfc_expr *target) if (target->expr_type == EXPR_NULL) goto null_arg; - if (target->expr_type == EXPR_VARIABLE) - attr2 = gfc_variable_attr (target, NULL); - else if (target->expr_type == EXPR_FUNCTION) - attr2 = target->symtree->n.sym->attr; + if (target->expr_type == EXPR_VARIABLE || target->expr_type == EXPR_FUNCTION) + attr2 = gfc_expr_attr (target); else { gfc_error ("'%s' argument of '%s' intrinsic at %L must be a pointer " diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 82442042dcc..08d2bd69ddf 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -1028,7 +1028,8 @@ verify_c_interop_param (gfc_symbol *sym) /* Build a polymorphic CLASS entity, using the symbol that comes from build_sym. A CLASS entity is represented by an encapsulating type, which contains the declared type as '$data' component, plus an integer component '$vindex' - which determines the dynamic type. */ + which determines the dynamic type, and another integer '$size', which + contains the size of the dynamic type structure. */ static gfc_try encapsulate_class_symbol (gfc_typespec *ts, symbol_attribute *attr, @@ -1077,6 +1078,7 @@ encapsulate_class_symbol (gfc_typespec *ts, symbol_attribute *attr, c->attr.pointer = attr->pointer || attr->dummy; c->attr.allocatable = attr->allocatable; c->attr.dimension = attr->dimension; + c->attr.abstract = ts->u.derived->attr.abstract; c->as = (*as); c->initializer = gfc_get_expr (); c->initializer->expr_type = EXPR_NULL; @@ -1088,6 +1090,14 @@ encapsulate_class_symbol (gfc_typespec *ts, symbol_attribute *attr, c->ts.kind = 4; c->attr.access = ACCESS_PRIVATE; c->initializer = gfc_int_expr (0); + + /* Add component '$size'. */ + if (gfc_add_component (fclass, "$size", &c) == FAILURE) + return FAILURE; + c->ts.type = BT_INTEGER; + c->ts.kind = 4; + c->attr.access = ACCESS_PRIVATE; + c->initializer = gfc_int_expr (0); } fclass->attr.extension = 1; @@ -1171,7 +1181,12 @@ build_sym (const char *name, gfc_charlen *cl, sym->attr.implied_index = 0; if (sym->ts.type == BT_CLASS) - encapsulate_class_symbol (&sym->ts, &sym->attr, &sym->as); + { + sym->attr.class_ok = (sym->attr.dummy + || sym->attr.pointer + || sym->attr.allocatable) ? 1 : 0; + encapsulate_class_symbol (&sym->ts, &sym->attr, &sym->as); + } return SUCCESS; } @@ -1462,10 +1477,11 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, gfc_array_spec **as) { gfc_component *c; + gfc_try t = SUCCESS; - /* If the current symbol is of the same derived type that we're + /* F03:C438/C439. 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 + if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS) && current_ts.u.derived == gfc_current_block () && current_attr.pointer == 0) { @@ -1544,12 +1560,9 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, } } - if (c->ts.type == BT_CLASS) - encapsulate_class_symbol (&c->ts, &c->attr, &c->as); - /* Check array components. */ if (!c->attr.dimension) - return SUCCESS; + goto scalar; if (c->attr.pointer) { @@ -1557,7 +1570,7 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, { gfc_error ("Pointer array component of structure at %C must have a " "deferred shape"); - return FAILURE; + t = FAILURE; } } else if (c->attr.allocatable) @@ -1566,7 +1579,7 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, { gfc_error ("Allocatable component of structure at %C must have a " "deferred shape"); - return FAILURE; + t = FAILURE; } } else @@ -1575,11 +1588,15 @@ build_struct (const char *name, gfc_charlen *cl, gfc_expr **init, { gfc_error ("Array component of structure at %C must have an " "explicit shape"); - return FAILURE; + t = FAILURE; } } - return SUCCESS; +scalar: + if (c->ts.type == BT_CLASS) + encapsulate_class_symbol (&c->ts, &c->attr, &c->as); + + return t; } @@ -3751,7 +3768,8 @@ gfc_match_data_decl (void) if (m != MATCH_YES) return m; - if (current_ts.type == BT_DERIVED && gfc_current_state () != COMP_DERIVED) + if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS) + && gfc_current_state () != COMP_DERIVED) { sym = gfc_use_derived (current_ts.u.derived); @@ -3771,7 +3789,8 @@ gfc_match_data_decl (void) goto cleanup; } - if (current_ts.type == BT_DERIVED && current_ts.u.derived->components == NULL + if ((current_ts.type == BT_DERIVED || current_ts.type == BT_CLASS) + && current_ts.u.derived->components == NULL && !current_ts.u.derived->attr.zero_comp) { @@ -5684,13 +5703,31 @@ attr_decl1 (void) } } - /* Update symbol table. DIMENSION attribute is set - in gfc_set_array_spec(). */ - if (current_attr.dimension == 0 - && gfc_copy_attr (&sym->attr, ¤t_attr, &var_locus) == FAILURE) + /* Update symbol table. DIMENSION attribute is set in + gfc_set_array_spec(). For CLASS variables, this must be applied + to the first component, or '$data' field. */ + if (sym->ts.type == BT_CLASS && sym->ts.u.derived) { - m = MATCH_ERROR; - goto cleanup; + gfc_component *comp; + comp = gfc_find_component (sym->ts.u.derived, "$data", true, true); + if (comp == NULL || gfc_copy_attr (&comp->attr, ¤t_attr, + &var_locus) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } + sym->attr.class_ok = (sym->attr.class_ok + || current_attr.allocatable + || current_attr.pointer); + } + else + { + if (current_attr.dimension == 0 + && gfc_copy_attr (&sym->attr, ¤t_attr, &var_locus) == FAILURE) + { + m = MATCH_ERROR; + goto cleanup; + } } if (gfc_set_array_spec (sym, as, &var_locus) == FAILURE) @@ -6746,8 +6783,44 @@ gfc_get_type_attr_spec (symbol_attribute *attr, char *name) } -/* Counter for assigning a unique vindex number to each derived type. */ -static int vindex_counter = 0; +/* Assign a hash value for a derived type. The algorithm is that of + SDBM. The hashed string is '[module_name #] derived_name'. */ +static unsigned int +hash_value (gfc_symbol *sym) +{ + unsigned int hash = 0; + const char *c; + int i, len; + + /* Hash of the module or procedure name. */ + if (sym->module != NULL) + c = sym->module; + else if (sym->ns && sym->ns->proc_name + && sym->ns->proc_name->attr.flavor == FL_MODULE) + c = sym->ns->proc_name->name; + else + c = NULL; + + if (c) + { + len = strlen (c); + for (i = 0; i < len; i++, c++) + hash = (hash << 6) + (hash << 16) - hash + (*c); + + /* Disambiguate between 'a' in 'aa' and 'aa' in 'a'. */ + hash = (hash << 6) + (hash << 16) - hash + '#'; + } + + /* Hash of the derived type name. */ + len = strlen (sym->name); + c = sym->name; + for (i = 0; i < len; i++, c++) + hash = (hash << 6) + (hash << 16) - hash + (*c); + + /* Return the hash but take the modulus for the sake of module read, + even though this slightly increases the chance of collision. */ + return (hash % 100000000); +} /* Match the beginning of a derived type declaration. If a type name @@ -6871,8 +6944,8 @@ gfc_match_derived_decl (void) } if (!sym->vindex) - /* Set the vindex for this type and increment the counter. */ - sym->vindex = ++vindex_counter; + /* Set the vindex for this type. */ + sym->vindex = hash_value (sym); /* Take over the ABSTRACT attribute. */ sym->attr.abstract = attr.abstract; diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index 32aa68265bb..cbd3172b454 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -3277,8 +3277,7 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue) return SUCCESS; } - if (lvalue->ts.type != BT_CLASS && lvalue->symtree->n.sym->ts.type != BT_CLASS - && !gfc_compare_types (&lvalue->ts, &rvalue->ts)) + if (!gfc_compare_types (&lvalue->ts, &rvalue->ts)) { gfc_error ("Different types in pointer assignment at %L; attempted " "assignment of %s to %s", &lvalue->where, diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index b40f01ba4bf..74a31d2661c 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -672,6 +672,7 @@ typedef struct unsigned is_bind_c:1; /* say if is bound to C. */ unsigned extension:1; /* extends a derived type. */ unsigned is_class:1; /* is a CLASS container. */ + unsigned class_ok:1; /* is a CLASS object with correct attributes. */ /* These flags are both in the typespec and attribute. The attribute list is what gets read from/written to a module file. The typespec @@ -1594,6 +1595,17 @@ typedef struct gfc_intrinsic_sym gfc_intrinsic_sym; +typedef struct gfc_class_esym_list +{ + gfc_symbol *derived; + gfc_symbol *esym; + struct gfc_expr *vindex; + struct gfc_class_esym_list *next; +} +gfc_class_esym_list; + +#define gfc_get_class_esym_list() XCNEW (gfc_class_esym_list) + /* Expression nodes. The expression node types deserve explanations, since the last couple can be easily misconstrued: @@ -1618,6 +1630,7 @@ gfc_intrinsic_sym; # endif # if MPC_VERSION >= MPC_VERSION_NUM(0,7,1) # define HAVE_mpc_arc +# define HAVE_mpc_pow_z # endif #else #define mpc_realref(X) ((X).r) @@ -1705,6 +1718,7 @@ typedef struct gfc_expr const char *name; /* Points to the ultimate name of the function */ gfc_intrinsic_sym *isym; gfc_symbol *esym; + gfc_class_esym_list *class_esym; } function; @@ -2195,6 +2209,18 @@ iterator_stack; extern iterator_stack *iter_stack; +/* Used for (possibly nested) SELECT TYPE statements. */ +typedef struct gfc_select_type_stack +{ + gfc_symbol *selector; /* Current selector variable. */ + gfc_symtree *tmp; /* Current temporary variable. */ + struct gfc_select_type_stack *prev; /* Previous element on stack. */ +} +gfc_select_type_stack; +extern gfc_select_type_stack *select_type_stack; +#define gfc_get_select_type_stack() XCNEW (gfc_select_type_stack) + + /* Node in the linked list used for storing finalizer procedures. */ typedef struct gfc_finalizer @@ -2553,10 +2579,6 @@ void gfc_free_equiv (gfc_equiv *); void gfc_free_data (gfc_data *); void gfc_free_case_list (gfc_case *); -/* Used for SELECT TYPE statements. */ -extern gfc_symbol *type_selector; -extern gfc_symtree *select_type_tmp; - /* matchexp.c -- FIXME too? */ gfc_expr *gfc_get_parentheses (gfc_expr *); diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 0fd4742a1de..866a81ca1d8 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -626,6 +626,7 @@ gfc_check_operator_interface (gfc_symbol *sym, gfc_intrinsic_op op, - Types and kinds do not conform, and - First argument is of derived type. */ if (sym->formal->sym->ts.type != BT_DERIVED + && sym->formal->sym->ts.type != BT_CLASS && (r1 == 0 || r1 == r2) && (sym->formal->sym->ts.type == sym->formal->next->sym->ts.type || (gfc_numeric_ts (&sym->formal->sym->ts) @@ -2573,13 +2574,16 @@ matching_typebound_op (gfc_expr** tb_base, gfc_actual_arglist* base; for (base = args; base; base = base->next) - if (base->expr->ts.type == BT_DERIVED) + if (base->expr->ts.type == BT_DERIVED || base->expr->ts.type == BT_CLASS) { gfc_typebound_proc* tb; gfc_symbol* derived; gfc_try result; - derived = base->expr->ts.u.derived; + if (base->expr->ts.type == BT_CLASS) + derived = base->expr->ts.u.derived->components->ts.u.derived; + else + derived = base->expr->ts.u.derived; if (op == INTRINSIC_USER) { @@ -2836,7 +2840,7 @@ gfc_extend_assign (gfc_code *c, gfc_namespace *ns) rhs = c->expr2; /* Don't allow an intrinsic assignment to be replaced. */ - if (lhs->ts.type != BT_DERIVED + if (lhs->ts.type != BT_DERIVED && lhs->ts.type != BT_CLASS && (rhs->rank == 0 || rhs->rank == lhs->rank) && (lhs->ts.type == rhs->ts.type || (gfc_numeric_ts (&lhs->ts) && gfc_numeric_ts (&rhs->ts)))) diff --git a/gcc/fortran/intrinsic.texi b/gcc/fortran/intrinsic.texi index 2c993b9048a..3aa16b0f860 100644 --- a/gcc/fortran/intrinsic.texi +++ b/gcc/fortran/intrinsic.texi @@ -2744,7 +2744,7 @@ Inverse function: @ref{ACOSH} @code{COUNT(MASK [, DIM [, KIND]])} counts the number of @code{.TRUE.} elements of @var{MASK} along the dimension of @var{DIM}. If @var{DIM} is omitted it is taken to be @code{1}. @var{DIM} is a scalar of type -@code{INTEGER} in the range of @math{1 /leq DIM /leq n)} where @math{n} +@code{INTEGER} in the range of @math{1 \leq DIM \leq n)} where @math{n} is the rank of @var{MASK}. @item @emph{Standard}: @@ -2864,7 +2864,7 @@ end program test_cpu_time @code{CSHIFT(ARRAY, SHIFT [, DIM])} performs a circular shift on elements of @var{ARRAY} along the dimension of @var{DIM}. If @var{DIM} is omitted it is taken to be @code{1}. @var{DIM} is a scalar of type @code{INTEGER} in the -range of @math{1 /leq DIM /leq n)} where @math{n} is the rank of @var{ARRAY}. +range of @math{1 \leq DIM \leq n)} where @math{n} is the rank of @var{ARRAY}. If the rank of @var{ARRAY} is one, then all elements of @var{ARRAY} are shifted by @var{SHIFT} places. If rank is greater than one, then all complete rank one sections of @var{ARRAY} along the given dimension are shifted. Elements @@ -3458,8 +3458,8 @@ Subroutine, function @item @emph{Arguments}: @multitable @columnfractions .15 .70 -@item @var{VALUES}@tab The type shall be @code{REAL, DIMENSION(2)}. -@item @var{TIME}@tab The type shall be @code{REAL}. +@item @var{VALUES}@tab The type shall be @code{REAL(4), DIMENSION(2)}. +@item @var{TIME}@tab The type shall be @code{REAL(4)}. @end multitable @item @emph{Return value}: @@ -3503,7 +3503,7 @@ end program test_dtime @code{EOSHIFT(ARRAY, SHIFT[, BOUNDARY, DIM])} performs an end-off shift on elements of @var{ARRAY} along the dimension of @var{DIM}. If @var{DIM} is omitted it is taken to be @code{1}. @var{DIM} is a scalar of type -@code{INTEGER} in the range of @math{1 /leq DIM /leq n)} where @math{n} is the +@code{INTEGER} in the range of @math{1 \leq DIM \leq n)} where @math{n} is the rank of @var{ARRAY}. If the rank of @var{ARRAY} is one, then all elements of @var{ARRAY} are shifted by @var{SHIFT} places. If rank is greater than one, then all complete rank one sections of @var{ARRAY} along the given dimension are @@ -3767,8 +3767,8 @@ Subroutine, function @item @emph{Arguments}: @multitable @columnfractions .15 .70 -@item @var{VALUES}@tab The type shall be @code{REAL, DIMENSION(2)}. -@item @var{TIME}@tab The type shall be @code{REAL}. +@item @var{VALUES}@tab The type shall be @code{REAL(4), DIMENSION(2)}. +@item @var{TIME}@tab The type shall be @code{REAL(4)}. @end multitable @item @emph{Return value}: diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c index abd370f5048..d6b64c4120c 100644 --- a/gcc/fortran/io.c +++ b/gcc/fortran/io.c @@ -643,6 +643,8 @@ format_item_1: case FMT_X: /* X requires a prior number if we're being pedantic. */ + if (mode != MODE_FORMAT) + format_locus.nextc += format_string_pos; if (gfc_notify_std (GFC_STD_GNU, "Extension: X descriptor " "requires leading space count at %L", &format_locus) == FAILURE) @@ -722,7 +724,7 @@ data_desc: break; case FMT_P: - /* Comma after P is allowed only for F, E, EN, ES, D, or G. + /* No comma after P allowed only for F, E, EN, ES, D, or G. 10.1.1 (1). */ t = format_lex (); if (t == FMT_ERROR) @@ -1052,7 +1054,7 @@ between_desc: default: if (mode != MODE_FORMAT) - format_locus.nextc += format_string_pos; + format_locus.nextc += format_string_pos - 1; if (gfc_notify_std (GFC_STD_GNU, "Extension: Missing comma at %L", &format_locus) == FAILURE) return FAILURE; diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c index 3e969e78ca2..24e292bd4d6 100644 --- a/gcc/fortran/match.c +++ b/gcc/fortran/match.c @@ -29,9 +29,8 @@ along with GCC; see the file COPYING3. If not see int gfc_matching_procptr_assignment = 0; bool gfc_matching_prefix = false; -/* Used for SELECT TYPE statements. */ -gfc_symbol *type_selector; -gfc_symtree *select_type_tmp; +/* Stack of SELECT TYPE statements. */ +gfc_select_type_stack *select_type_stack = NULL; /* For debugging and diagnostic purposes. Return the textual representation of the intrinsic operator OP. */ @@ -2389,58 +2388,6 @@ char_selector: } -/* Used in gfc_match_allocate to check that a allocation-object and - a source-expr are conformable. This does not catch all possible - cases; in particular a runtime checking is needed. */ - -static gfc_try -conformable_arrays (gfc_expr *e1, gfc_expr *e2) -{ - /* First compare rank. */ - if (e2->ref && e1->rank != e2->ref->u.ar.as->rank) - { - gfc_error ("Source-expr at %L must be scalar or have the " - "same rank as the allocate-object at %L", - &e1->where, &e2->where); - return FAILURE; - } - - if (e1->shape) - { - int i; - mpz_t s; - - mpz_init (s); - - for (i = 0; i < e1->rank; i++) - { - if (e2->ref->u.ar.end[i]) - { - mpz_set (s, e2->ref->u.ar.end[i]->value.integer); - mpz_sub (s, s, e2->ref->u.ar.start[i]->value.integer); - mpz_add_ui (s, s, 1); - } - else - { - mpz_set (s, e2->ref->u.ar.start[i]->value.integer); - } - - if (mpz_cmp (e1->shape[i], s) != 0) - { - gfc_error ("Source-expr at %L and allocate-object at %L must " - "have the same shape", &e1->where, &e2->where); - mpz_clear (s); - return FAILURE; - } - } - - mpz_clear (s); - } - - return SUCCESS; -} - - /* Match an ALLOCATE statement. */ match @@ -2621,7 +2568,7 @@ alloc_opt_list: goto cleanup; } - /* The next 3 conditionals check C631. */ + /* The next 2 conditionals check C631. */ if (ts.type != BT_UNKNOWN) { gfc_error ("SOURCE tag at %L conflicts with the typespec at %L", @@ -2636,28 +2583,6 @@ alloc_opt_list: goto cleanup; } - gfc_resolve_expr (tmp); - - if (!gfc_type_compatible (&head->expr->ts, &tmp->ts)) - { - gfc_error ("Type of entity at %L is type incompatible with " - "source-expr at %L", &head->expr->where, &tmp->where); - goto cleanup; - } - - /* Check C633. */ - if (tmp->ts.kind != head->expr->ts.kind) - { - gfc_error ("The allocate-object at %L and the source-expr at %L " - "shall have the same kind type parameter", - &head->expr->where, &tmp->where); - goto cleanup; - } - - /* Check C632 and restriction following Note 6.18. */ - if (tmp->rank > 0 && conformable_arrays (tmp, head->expr) == FAILURE) - goto cleanup; - source = tmp; saw_source = true; @@ -3751,7 +3676,10 @@ gfc_match_equivalence (void) if (gfc_match_eos () == MATCH_YES) break; if (gfc_match_char (',') != MATCH_YES) - goto syntax; + { + gfc_error ("Expecting a comma in EQUIVALENCE at %C"); + goto cleanup; + } } return MATCH_YES; @@ -4021,46 +3949,90 @@ gfc_match_select (void) } +/* Push the current selector onto the SELECT TYPE stack. */ + +static void +select_type_push (gfc_symbol *sel) +{ + gfc_select_type_stack *top = gfc_get_select_type_stack (); + top->selector = sel; + top->tmp = NULL; + top->prev = select_type_stack; + + select_type_stack = top; +} + + +/* Set the temporary for the current SELECT TYPE selector. */ + +static void +select_type_set_tmp (gfc_typespec *ts) +{ + char name[GFC_MAX_SYMBOL_LEN]; + gfc_symtree *tmp; + + sprintf (name, "tmp$%s", ts->u.derived->name); + gfc_get_sym_tree (name, gfc_current_ns, &tmp, false); + gfc_add_type (tmp->n.sym, ts, NULL); + gfc_set_sym_referenced (tmp->n.sym); + gfc_add_pointer (&tmp->n.sym->attr, NULL); + gfc_add_flavor (&tmp->n.sym->attr, FL_VARIABLE, name, NULL); + + select_type_stack->tmp = tmp; +} + + /* Match a SELECT TYPE statement. */ match gfc_match_select_type (void) { - gfc_expr *expr; + gfc_expr *expr1, *expr2 = NULL; match m; + char name[GFC_MAX_SYMBOL_LEN]; m = gfc_match_label (); if (m == MATCH_ERROR) return m; - m = gfc_match (" select type ( %e ", &expr); + m = gfc_match (" select type ( "); if (m != MATCH_YES) return m; - /* TODO: Implement ASSOCIATE. */ - m = gfc_match (" => "); + gfc_current_ns = gfc_build_block_ns (gfc_current_ns); + + m = gfc_match (" %n => %e", name, &expr2); if (m == MATCH_YES) { - gfc_error ("Associate-name in SELECT TYPE statement at %C " - "is not yet supported"); - return MATCH_ERROR; + expr1 = gfc_get_expr(); + expr1->expr_type = EXPR_VARIABLE; + if (gfc_get_sym_tree (name, NULL, &expr1->symtree, false)) + return MATCH_ERROR; + expr1->symtree->n.sym->ts = expr2->ts; + expr1->symtree->n.sym->attr.referenced = 1; + expr1->symtree->n.sym->attr.class_ok = 1; + } + else + { + m = gfc_match (" %e ", &expr1); + if (m != MATCH_YES) + return m; } m = gfc_match (" )%t"); if (m != MATCH_YES) return m; - /* Check for F03:C811. - TODO: Change error message once ASSOCIATE is implemented. */ - if (expr->expr_type != EXPR_VARIABLE || expr->ref != NULL) + /* Check for F03:C811. */ + if (!expr2 && (expr1->expr_type != EXPR_VARIABLE || expr1->ref != NULL)) { - gfc_error ("Selector must be a named variable in SELECT TYPE statement " - "at %C"); + gfc_error ("Selector in SELECT TYPE at %C is not a named variable; " + "use associate-name=>"); return MATCH_ERROR; } /* Check for F03:C813. */ - if (expr->ts.type != BT_CLASS) + if (expr1->ts.type != BT_CLASS && !(expr2 && expr2->ts.type == BT_CLASS)) { gfc_error ("Selector shall be polymorphic in SELECT TYPE statement " "at %C"); @@ -4068,9 +4040,11 @@ gfc_match_select_type (void) } new_st.op = EXEC_SELECT_TYPE; - new_st.expr1 = expr; + new_st.expr1 = expr1; + new_st.expr2 = expr2; + new_st.ext.ns = gfc_current_ns; - type_selector = expr->symtree->n.sym; + select_type_push (expr1->symtree->n.sym); return MATCH_YES; } @@ -4155,7 +4129,6 @@ gfc_match_type_is (void) { gfc_case *c = NULL; match m; - char name[GFC_MAX_SYMBOL_LEN]; if (gfc_current_state () != COMP_SELECT_TYPE) { @@ -4187,11 +4160,7 @@ gfc_match_type_is (void) new_st.ext.case_list = c; /* Create temporary variable. */ - sprintf (name, "tmp$%s", c->ts.u.derived->name); - gfc_get_sym_tree (name, gfc_current_ns, &select_type_tmp, false); - select_type_tmp->n.sym->ts = c->ts; - select_type_tmp->n.sym->attr.referenced = 1; - select_type_tmp->n.sym->attr.pointer = 1; + select_type_set_tmp (&c->ts); return MATCH_YES; diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c index 1769eada5fe..b2ad6ecc477 100644 --- a/gcc/fortran/module.c +++ b/gcc/fortran/module.c @@ -3972,6 +3972,72 @@ load_equiv (void) } +/* This function loads the sym_root of f2k_derived with the extensions to + the derived type. */ +static void +load_derived_extensions (void) +{ + int symbol, nuse, j; + gfc_symbol *derived; + gfc_symbol *dt; + gfc_symtree *st; + pointer_info *info; + char name[GFC_MAX_SYMBOL_LEN + 1]; + char module[GFC_MAX_SYMBOL_LEN + 1]; + const char *p; + + mio_lparen (); + while (peek_atom () != ATOM_RPAREN) + { + mio_lparen (); + mio_integer (&symbol); + info = get_integer (symbol); + derived = info->u.rsym.sym; + + /* This one is not being loaded. */ + if (!info || !derived) + { + while (peek_atom () != ATOM_RPAREN) + skip_list (); + continue; + } + + gcc_assert (derived->attr.flavor == FL_DERIVED); + if (derived->f2k_derived == NULL) + derived->f2k_derived = gfc_get_namespace (NULL, 0); + + while (peek_atom () != ATOM_RPAREN) + { + mio_lparen (); + mio_internal_string (name); + mio_internal_string (module); + + /* Only use one use name to find the symbol. */ + nuse = number_use_names (name, false); + j = 1; + p = find_use_name_n (name, &j, false); + if (p) + { + st = gfc_find_symtree (gfc_current_ns->sym_root, p); + dt = st->n.sym; + st = gfc_find_symtree (derived->f2k_derived->sym_root, name); + if (st == NULL) + { + /* Only use the real name in f2k_derived to ensure a single + symtree. */ + st = gfc_new_symtree (&derived->f2k_derived->sym_root, name); + st->n.sym = dt; + st->n.sym->refs++; + } + } + mio_rparen (); + } + mio_rparen (); + } + 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. */ @@ -4113,7 +4179,7 @@ check_for_ambiguous (gfc_symbol *st_sym, pointer_info *info) static void read_module (void) { - module_locus operator_interfaces, user_operators; + module_locus operator_interfaces, user_operators, extensions; const char *p; char name[GFC_MAX_SYMBOL_LEN + 1]; int i; @@ -4130,10 +4196,13 @@ read_module (void) skip_list (); skip_list (); - /* Skip commons and equivalences for now. */ + /* Skip commons, equivalences and derived type extensions for now. */ skip_list (); skip_list (); + get_module_locus (&extensions); + skip_list (); + mio_lparen (); /* Create the fixup nodes for all the symbols. */ @@ -4386,6 +4455,11 @@ read_module (void) gfc_check_interfaces (gfc_current_ns); + /* Now we should be in a position to fill f2k_derived with derived type + extensions, since everything has been loaded. */ + set_module_locus (&extensions); + load_derived_extensions (); + /* Clean up symbol nodes that were never loaded, create references to hidden symbols. */ @@ -4594,6 +4668,36 @@ write_equiv (void) } +/* Write derived type extensions to the module. */ + +static void +write_dt_extensions (gfc_symtree *st) +{ + mio_lparen (); + mio_pool_string (&st->n.sym->name); + if (st->n.sym->module != NULL) + mio_pool_string (&st->n.sym->module); + else + mio_internal_string (module_name); + mio_rparen (); +} + +static void +write_derived_extensions (gfc_symtree *st) +{ + if (!((st->n.sym->attr.flavor == FL_DERIVED) + && (st->n.sym->f2k_derived != NULL) + && (st->n.sym->f2k_derived->sym_root != NULL))) + return; + + mio_lparen (); + mio_symbol_ref (&(st->n.sym)); + gfc_traverse_symtree (st->n.sym->f2k_derived->sym_root, + write_dt_extensions); + mio_rparen (); +} + + /* Write a symbol to the module. */ static void @@ -4820,6 +4924,13 @@ write_module (void) write_char ('\n'); write_char ('\n'); + mio_lparen (); + gfc_traverse_symtree (gfc_current_ns->sym_root, + write_derived_extensions); + 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 diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c index 3e20f8e45d4..3742addb6b1 100644 --- a/gcc/fortran/options.c +++ b/gcc/fortran/options.c @@ -242,6 +242,10 @@ gfc_post_options (const char **pfilename) if (flag_whole_program) gfc_option.flag_whole_file = 1; + /* Enable whole-file mode if LTO is in effect. */ + if (flag_lto || flag_whopr) + gfc_option.flag_whole_file = 1; + /* -fbounds-check is equivalent to -fcheck=bounds */ if (flag_bounds_check) gfc_option.rtcheck |= GFC_RTCHECK_BOUNDS; diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 13199c91bb0..95a327bf23d 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -2068,11 +2068,15 @@ endType: { /* Look for allocatable components. */ if (c->attr.allocatable + || (c->ts.type == BT_CLASS + && c->ts.u.derived->components->attr.allocatable) || (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.alloc_comp)) sym->attr.alloc_comp = 1; /* Look for pointer components. */ if (c->attr.pointer + || (c->ts.type == BT_CLASS + && c->ts.u.derived->components->attr.pointer) || (c->ts.type == BT_DERIVED && c->ts.u.derived->attr.pointer_comp)) sym->attr.pointer_comp = 1; @@ -2887,6 +2891,17 @@ parse_select_block (void) } +/* Pop the current selector from the SELECT TYPE stack. */ + +static void +select_type_pop (void) +{ + gfc_select_type_stack *old = select_type_stack; + select_type_stack = old->prev; + gfc_free (old); +} + + /* Parse a SELECT TYPE construct (F03:R821). */ static void @@ -2909,12 +2924,8 @@ parse_select_type_block (void) if (st == ST_NONE) unexpected_eof (); if (st == ST_END_SELECT) - { - /* Empty SELECT CASE is OK. */ - accept_statement (st); - pop_state (); - return; - } + /* Empty SELECT CASE is OK. */ + goto done; if (st == ST_TYPE_IS || st == ST_CLASS_IS) break; @@ -2959,8 +2970,11 @@ parse_select_type_block (void) } while (st != ST_END_SELECT); +done: pop_state (); accept_statement (st); + gfc_current_ns = gfc_current_ns->parent; + select_type_pop (); } @@ -3033,18 +3047,13 @@ check_do_closure (void) static void parse_progunit (gfc_statement); -/* Parse a BLOCK construct. */ +/* Set up the local namespace for a BLOCK construct. */ -static void -parse_block_construct (void) +gfc_namespace* +gfc_build_block_ns (gfc_namespace *parent_ns) { - gfc_namespace* parent_ns; gfc_namespace* my_ns; - gfc_state_data s; - - gfc_notify_std (GFC_STD_F2008, "Fortran 2008: BLOCK construct at %C"); - parent_ns = gfc_current_ns; my_ns = gfc_get_namespace (parent_ns, 1); my_ns->construct_entities = 1; @@ -3064,7 +3073,25 @@ parse_block_construct (void) my_ns->proc_name->name, NULL); gcc_assert (t == SUCCESS); } - my_ns->proc_name->attr.recursive = parent_ns->proc_name->attr.recursive; + + if (parent_ns->proc_name) + my_ns->proc_name->attr.recursive = parent_ns->proc_name->attr.recursive; + + return my_ns; +} + + +/* Parse a BLOCK construct. */ + +static void +parse_block_construct (void) +{ + gfc_namespace* my_ns; + gfc_state_data s; + + gfc_notify_std (GFC_STD_F2008, "Fortran 2008: BLOCK construct at %C"); + + my_ns = gfc_build_block_ns (gfc_current_ns); new_st.op = EXEC_BLOCK; new_st.ext.ns = my_ns; @@ -3075,7 +3102,7 @@ parse_block_construct (void) parse_progunit (ST_NONE); - gfc_current_ns = parent_ns; + gfc_current_ns = gfc_current_ns->parent; pop_state (); } diff --git a/gcc/fortran/parse.h b/gcc/fortran/parse.h index 2b926618d28..e0a2969c2a3 100644 --- a/gcc/fortran/parse.h +++ b/gcc/fortran/parse.h @@ -70,4 +70,5 @@ match gfc_match_enumerator_def (void); void gfc_free_enum_history (void); extern bool gfc_matching_function; match gfc_match_prefix (gfc_typespec *); +gfc_namespace* gfc_build_block_ns (gfc_namespace *); #endif /* GFC_PARSE_H */ diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index bb803b3475c..a721d944b33 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -367,15 +367,26 @@ resolve_contained_fntype (gfc_symbol *sym, gfc_namespace *ns) /* Fortran 95 Draft Standard, page 51, Section 5.1.1.5, on the Character type, lists the only ways a character length value of * can be used: dummy arguments of procedures, named constants, and function results - in external functions. Internal function results are not on that list; - ergo, not permitted. */ + in external functions. Internal function results and results of module + procedures are not on this list, ergo, not permitted. */ if (sym->result->ts.type == BT_CHARACTER) { gfc_charlen *cl = sym->result->ts.u.cl; if (!cl || !cl->length) - gfc_error ("Character-valued internal function '%s' at %L must " - "not be assumed length", sym->name, &sym->declared_at); + { + /* See if this is a module-procedure and adapt error message + accordingly. */ + bool module_proc; + gcc_assert (ns->parent && ns->parent->proc_name); + module_proc = (ns->parent->proc_name->attr.flavor == FL_MODULE); + + gfc_error ("Character-valued %s '%s' at %L must not be" + " assumed length", + module_proc ? _("module procedure") + : _("internal function"), + sym->name, &sym->declared_at); + } } } @@ -2515,7 +2526,9 @@ resolve_function (gfc_expr *expr) return FAILURE; } - if (sym && sym->attr.abstract) + /* If this ia a deferred TBP with an abstract interface (which may + of course be referenced), expr->value.function.name will be set. */ + if (sym && sym->attr.abstract && !expr->value.function.name) { gfc_error ("ABSTRACT INTERFACE '%s' must not be referenced at %L", sym->name, &expr->where); @@ -3127,6 +3140,15 @@ resolve_call (gfc_code *c) } } + /* If this ia a deferred TBP with an abstract interface + (which may of course be referenced), c->expr1 will be set. */ + if (csym && csym->attr.abstract && !c->expr1) + { + gfc_error ("ABSTRACT INTERFACE '%s' must not be referenced at %L", + csym->name, &c->loc); + return FAILURE; + } + /* Subroutines without the RECURSIVE attribution are not allowed to * call themselves. */ if (csym && is_illegal_recursion (csym, gfc_current_ns)) @@ -4997,28 +5019,42 @@ resolve_typebound_call (gfc_code* c) c->op = (c->expr1->value.compcall.assign ? EXEC_ASSIGN_CALL : EXEC_CALL); gcc_assert (!c->expr1->ref && !c->expr1->value.compcall.actual); + gfc_free_expr (c->expr1); - c->expr1 = NULL; + c->expr1 = gfc_get_expr (); + c->expr1->expr_type = EXPR_FUNCTION; + c->expr1->symtree = target; + c->expr1->where = c->loc; return resolve_call (c); } -/* Resolve a component-call expression. */ - +/* Resolve a component-call expression. This originally was intended + only to see functions. However, it is convenient to use it in + resolving subroutine class methods, since we do not have to add a + gfc_code each time. */ static gfc_try -resolve_compcall (gfc_expr* e) +resolve_compcall (gfc_expr* e, bool fcn) { gfc_actual_arglist* newactual; gfc_symtree* target; /* Check that's really a FUNCTION. */ - if (!e->value.compcall.tbp->function) + if (fcn && !e->value.compcall.tbp->function) { gfc_error ("'%s' at %L should be a FUNCTION", e->value.compcall.name, &e->where); return FAILURE; } + else if (!fcn && !e->value.compcall.tbp->subroutine) + { + /* To resolve class member calls, we borrow this bit + of code to select the specific procedures. */ + gfc_error ("'%s' at %L should be a SUBROUTINE", + e->value.compcall.name, &e->where); + return FAILURE; + } /* These must not be assign-calls! */ gcc_assert (!e->value.compcall.assign); @@ -5043,12 +5079,337 @@ resolve_compcall (gfc_expr* e) e->value.function.actual = newactual; e->value.function.name = e->value.compcall.name; e->value.function.esym = target->n.sym; + e->value.function.class_esym = NULL; e->value.function.isym = NULL; e->symtree = target; e->ts = target->n.sym->ts; e->expr_type = EXPR_FUNCTION; - return gfc_resolve_expr (e); + /* Resolution is not necessary if this is a class subroutine; this + function only has to identify the specific proc. Resolution of + the call will be done next in resolve_typebound_call. */ + return fcn ? gfc_resolve_expr (e) : SUCCESS; +} + + +/* Resolve a typebound call for the members in a class. This group of + functions implements dynamic dispatch in the provisional version + of f03 OOP. As soon as vtables are in place and contain pointers + to methods, this will no longer be necessary. */ +static gfc_expr *list_e; +static void check_class_members (gfc_symbol *); +static gfc_try class_try; +static bool fcn_flag; +static gfc_symbol *class_object; + + +static void +check_members (gfc_symbol *derived) +{ + if (derived->attr.flavor == FL_DERIVED) + check_class_members (derived); +} + + +static void +check_class_members (gfc_symbol *derived) +{ + gfc_symbol* tbp_sym; + gfc_expr *e; + gfc_symtree *tbp; + gfc_class_esym_list *etmp; + + e = gfc_copy_expr (list_e); + + tbp = gfc_find_typebound_proc (derived, &class_try, + e->value.compcall.name, + false, &e->where); + + if (tbp == NULL) + { + gfc_error ("no typebound available procedure named '%s' at %L", + e->value.compcall.name, &e->where); + return; + } + + if (tbp->n.tb->is_generic) + { + tbp_sym = NULL; + + /* If we have to match a passed class member, force the actual + expression to have the correct type. */ + if (!tbp->n.tb->nopass) + { + if (e->value.compcall.base_object == NULL) + e->value.compcall.base_object = + extract_compcall_passed_object (e); + + e->value.compcall.base_object->ts.type = BT_DERIVED; + e->value.compcall.base_object->ts.u.derived = derived; + } + } + else + tbp_sym = tbp->n.tb->u.specific->n.sym; + + e->value.compcall.tbp = tbp->n.tb; + e->value.compcall.name = tbp->name; + + /* Let the original expresssion catch the assertion in + resolve_compcall, since this flag does not appear to be reset or + copied in some systems. */ + e->value.compcall.assign = 0; + + /* Do the renaming, PASSing, generic => specific and other + good things for each class member. */ + class_try = (resolve_compcall (e, fcn_flag) == SUCCESS) + ? class_try : FAILURE; + + /* Now transfer the found symbol to the esym list. */ + if (class_try == SUCCESS) + { + etmp = list_e->value.function.class_esym; + list_e->value.function.class_esym + = gfc_get_class_esym_list(); + list_e->value.function.class_esym->next = etmp; + list_e->value.function.class_esym->derived = derived; + list_e->value.function.class_esym->esym + = e->value.function.esym; + } + + gfc_free_expr (e); + + /* Burrow down into grandchildren types. */ + if (derived->f2k_derived) + gfc_traverse_ns (derived->f2k_derived, check_members); +} + + +/* Eliminate esym_lists where all the members point to the + typebound procedure of the declared type; ie. one where + type selection has no effect.. */ +static void +resolve_class_esym (gfc_expr *e) +{ + gfc_class_esym_list *p, *q; + bool empty = true; + + gcc_assert (e && e->expr_type == EXPR_FUNCTION); + + p = e->value.function.class_esym; + if (p == NULL) + return; + + for (; p; p = p->next) + empty = empty && (e->value.function.esym == p->esym); + + if (empty) + { + p = e->value.function.class_esym; + for (; p; p = q) + { + q = p->next; + gfc_free (p); + } + e->value.function.class_esym = NULL; + } +} + + +/* Generate an expression for the vindex, given the reference to + the class of the final expression (class_ref), the base of the + full reference list (new_ref), the declared type and the class + object (st). */ +static gfc_expr* +vindex_expr (gfc_ref *class_ref, gfc_ref *new_ref, + gfc_symbol *declared, gfc_symtree *st) +{ + gfc_expr *vindex; + gfc_ref *ref; + + /* Build an expression for the correct vindex; ie. that of the last + CLASS reference. */ + ref = gfc_get_ref(); + ref->type = REF_COMPONENT; + ref->u.c.component = declared->components->next; + ref->u.c.sym = declared; + ref->next = NULL; + if (class_ref) + { + class_ref->next = ref; + } + else + { + gfc_free_ref_list (new_ref); + new_ref = ref; + } + vindex = gfc_get_expr (); + vindex->expr_type = EXPR_VARIABLE; + vindex->symtree = st; + vindex->symtree->n.sym->refs++; + vindex->ts = ref->u.c.component->ts; + vindex->ref = new_ref; + + return vindex; +} + + +/* Get the ultimate declared type from an expression. In addition, + return the last class/derived type reference and the copy of the + reference list. */ +static gfc_symbol* +get_declared_from_expr (gfc_ref **class_ref, gfc_ref **new_ref, + gfc_expr *e) +{ + gfc_symbol *declared; + gfc_ref *ref; + + declared = NULL; + *class_ref = NULL; + *new_ref = gfc_copy_ref (e->ref); + for (ref = *new_ref; ref; ref = ref->next) + { + if (ref->type != REF_COMPONENT) + continue; + + if (ref->u.c.component->ts.type == BT_CLASS + || ref->u.c.component->ts.type == BT_DERIVED) + { + declared = ref->u.c.component->ts.u.derived; + *class_ref = ref; + } + } + + if (declared == NULL) + declared = e->symtree->n.sym->ts.u.derived; + + return declared; +} + + +/* Resolve the argument expressions so that any arguments expressions + that include class methods are resolved before the current call. + This is necessary because of the static variables used in CLASS + method resolution. */ +static void +resolve_arg_exprs (gfc_actual_arglist *arg) +{ + /* Resolve the actual arglist expressions. */ + for (; arg; arg = arg->next) + { + if (arg->expr) + gfc_resolve_expr (arg->expr); + } +} + + +/* Resolve a CLASS typebound function, or 'method'. */ +static gfc_try +resolve_class_compcall (gfc_expr* e) +{ + gfc_symbol *derived, *declared; + gfc_ref *new_ref; + gfc_ref *class_ref; + gfc_symtree *st; + + st = e->symtree; + class_object = st->n.sym; + + /* Get the CLASS declared type. */ + declared = get_declared_from_expr (&class_ref, &new_ref, e); + + /* Weed out cases of the ultimate component being a derived type. */ + if (class_ref && class_ref->u.c.component->ts.type == BT_DERIVED) + { + gfc_free_ref_list (new_ref); + return resolve_compcall (e, true); + } + + /* Resolve the argument expressions, */ + resolve_arg_exprs (e->value.function.actual); + + /* Get the data component, which is of the declared type. */ + derived = declared->components->ts.u.derived; + + /* Resolve the function call for each member of the class. */ + class_try = SUCCESS; + fcn_flag = true; + list_e = gfc_copy_expr (e); + check_class_members (derived); + + class_try = (resolve_compcall (e, true) == SUCCESS) + ? class_try : FAILURE; + + /* Transfer the class list to the original expression. Note that + the class_esym list is cleaned up in trans-expr.c, as the calls + are translated. */ + e->value.function.class_esym = list_e->value.function.class_esym; + list_e->value.function.class_esym = NULL; + gfc_free_expr (list_e); + + resolve_class_esym (e); + + /* More than one typebound procedure so transmit an expression for + the vindex as the selector. */ + if (e->value.function.class_esym != NULL) + e->value.function.class_esym->vindex + = vindex_expr (class_ref, new_ref, declared, st); + + return class_try; +} + +/* Resolve a CLASS typebound subroutine, or 'method'. */ +static gfc_try +resolve_class_typebound_call (gfc_code *code) +{ + gfc_symbol *derived, *declared; + gfc_ref *new_ref; + gfc_ref *class_ref; + gfc_symtree *st; + + st = code->expr1->symtree; + class_object = st->n.sym; + + /* Get the CLASS declared type. */ + declared = get_declared_from_expr (&class_ref, &new_ref, code->expr1); + + /* Weed out cases of the ultimate component being a derived type. */ + if (class_ref && class_ref->u.c.component->ts.type == BT_DERIVED) + { + gfc_free_ref_list (new_ref); + return resolve_typebound_call (code); + } + + /* Resolve the argument expressions, */ + resolve_arg_exprs (code->expr1->value.compcall.actual); + + /* Get the data component, which is of the declared type. */ + derived = declared->components->ts.u.derived; + + class_try = SUCCESS; + fcn_flag = false; + list_e = gfc_copy_expr (code->expr1); + check_class_members (derived); + + class_try = (resolve_typebound_call (code) == SUCCESS) + ? class_try : FAILURE; + + /* Transfer the class list to the original expression. Note that + the class_esym list is cleaned up in trans-expr.c, as the calls + are translated. */ + code->expr1->value.function.class_esym + = list_e->value.function.class_esym; + list_e->value.function.class_esym = NULL; + gfc_free_expr (list_e); + + resolve_class_esym (code->expr1); + + /* More than one typebound procedure so transmit an expression for + the vindex as the selector. */ + if (code->expr1->value.function.class_esym != NULL) + code->expr1->value.function.class_esym->vindex + = vindex_expr (class_ref, new_ref, declared, st); + + return class_try; } @@ -5162,7 +5523,10 @@ gfc_resolve_expr (gfc_expr *e) break; case EXPR_COMPCALL: - t = resolve_compcall (e); + if (e->symtree && e->symtree->n.sym->ts.type == BT_CLASS) + t = resolve_class_compcall (e); + else + t = resolve_compcall (e, true); break; case EXPR_SUBSTRING: @@ -5605,6 +5969,58 @@ gfc_expr_to_initialize (gfc_expr *e) } +/* Used in resolve_allocate_expr to check that a allocation-object and + a source-expr are conformable. This does not catch all possible + cases; in particular a runtime checking is needed. */ + +static gfc_try +conformable_arrays (gfc_expr *e1, gfc_expr *e2) +{ + /* First compare rank. */ + if (e2->ref && e1->rank != e2->ref->u.ar.as->rank) + { + gfc_error ("Source-expr at %L must be scalar or have the " + "same rank as the allocate-object at %L", + &e1->where, &e2->where); + return FAILURE; + } + + if (e1->shape) + { + int i; + mpz_t s; + + mpz_init (s); + + for (i = 0; i < e1->rank; i++) + { + if (e2->ref->u.ar.end[i]) + { + mpz_set (s, e2->ref->u.ar.end[i]->value.integer); + mpz_sub (s, s, e2->ref->u.ar.start[i]->value.integer); + mpz_add_ui (s, s, 1); + } + else + { + mpz_set (s, e2->ref->u.ar.start[i]->value.integer); + } + + if (mpz_cmp (e1->shape[i], s) != 0) + { + gfc_error ("Source-expr at %L and allocate-object at %L must " + "have the same shape", &e1->where, &e2->where); + mpz_clear (s); + return FAILURE; + } + } + + mpz_clear (s); + } + + 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. */ @@ -5612,11 +6028,10 @@ gfc_expr_to_initialize (gfc_expr *e) static gfc_try resolve_allocate_expr (gfc_expr *e, gfc_code *code) { - int i, pointer, allocatable, dimension, check_intent_in; + int i, pointer, allocatable, dimension, check_intent_in, is_abstract; symbol_attribute attr; gfc_ref *ref, *ref2; gfc_array_ref *ar; - gfc_code *init_st; gfc_symbol *sym; gfc_alloc *a; gfc_component *c; @@ -5634,6 +6049,9 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) if (e->symtree) sym = e->symtree->n.sym; + /* Check whether ultimate component is abstract and CLASS. */ + is_abstract = 0; + if (e->expr_type != EXPR_VARIABLE) { allocatable = 0; @@ -5648,6 +6066,7 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) allocatable = sym->ts.u.derived->components->attr.allocatable; pointer = sym->ts.u.derived->components->attr.pointer; dimension = sym->ts.u.derived->components->attr.dimension; + is_abstract = sym->ts.u.derived->components->attr.abstract; } else { @@ -5675,12 +6094,14 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) allocatable = c->ts.u.derived->components->attr.allocatable; pointer = c->ts.u.derived->components->attr.pointer; dimension = c->ts.u.derived->components->attr.dimension; + is_abstract = c->ts.u.derived->components->attr.abstract; } else { allocatable = c->attr.allocatable; pointer = c->attr.pointer; dimension = c->attr.dimension; + is_abstract = c->attr.abstract; } break; @@ -5699,46 +6120,44 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code) return FAILURE; } - if (check_intent_in && sym->attr.intent == INTENT_IN) - { - gfc_error ("Cannot allocate INTENT(IN) variable '%s' at %L", - sym->name, &e->where); - return FAILURE; - } - - if (e->ts.type == BT_CLASS) + /* Some checks for the SOURCE tag. */ + if (code->expr3) { - /* Initialize VINDEX for CLASS objects. */ - init_st = gfc_get_code (); - init_st->loc = code->loc; - init_st->expr1 = gfc_expr_to_initialize (e); - init_st->op = EXEC_ASSIGN; - gfc_add_component_ref (init_st->expr1, "$vindex"); - if (code->expr3 && code->expr3->ts.type == BT_CLASS) + /* Check F03:C631. */ + if (!gfc_type_compatible (&e->ts, &code->expr3->ts)) { - /* vindex must be determined at run time. */ - init_st->expr2 = gfc_copy_expr (code->expr3); - gfc_add_component_ref (init_st->expr2, "$vindex"); + gfc_error ("Type of entity at %L is type incompatible with " + "source-expr at %L", &e->where, &code->expr3->where); + return FAILURE; } - else + + /* Check F03:C632 and restriction following Note 6.18. */ + if (code->expr3->rank > 0 + && conformable_arrays (code->expr3, e) == FAILURE) + return FAILURE; + + /* Check F03:C633. */ + if (code->expr3->ts.kind != e->ts.kind) { - /* vindex is fixed at compile time. */ - int vindex; - if (code->expr3) - vindex = code->expr3->ts.u.derived->vindex; - else if (code->ext.alloc.ts.type == BT_DERIVED) - vindex = code->ext.alloc.ts.u.derived->vindex; - else if (e->ts.type == BT_CLASS) - vindex = e->ts.u.derived->components->ts.u.derived->vindex; - else - vindex = e->ts.u.derived->vindex; - init_st->expr2 = gfc_int_expr (vindex); + gfc_error ("The allocate-object at %L and the source-expr at %L " + "shall have the same kind type parameter", + &e->where, &code->expr3->where); + return FAILURE; } - init_st->expr2->where = init_st->expr1->where = init_st->loc; - init_st->next = code->next; - code->next = init_st; - /* Only allocate the DATA component. */ - gfc_add_component_ref (e, "$data"); + } + else if (is_abstract&& code->ext.alloc.ts.type == BT_UNKNOWN) + { + gcc_assert (e->ts.type == BT_CLASS); + gfc_error ("Allocating %s of ABSTRACT base type at %L requires a " + "type-spec or SOURCE=", sym->name, &e->where); + return FAILURE; + } + + if (check_intent_in && sym->attr.intent == INTENT_IN) + { + gfc_error ("Cannot allocate INTENT(IN) variable '%s' at %L", + sym->name, &e->where); + return FAILURE; } if (pointer || dimension == 0) @@ -5790,7 +6209,7 @@ check_symbols: sym = a->expr->symtree->n.sym; /* TODO - check derived type components. */ - if (sym->ts.type == BT_DERIVED) + if (sym->ts.type == BT_DERIVED || sym->ts.type == BT_CLASS) continue; if ((ar->start[i] != NULL @@ -6444,8 +6863,15 @@ resolve_select_type (gfc_code *code) gfc_case *c, *default_case; gfc_symtree *st; char name[GFC_MAX_SYMBOL_LEN]; + gfc_namespace *ns; - selector_type = code->expr1->ts.u.derived->components->ts.u.derived; + ns = code->ext.ns; + gfc_resolve (ns); + + if (code->expr2) + selector_type = code->expr2->ts.u.derived->components->ts.u.derived; + else + selector_type = code->expr1->ts.u.derived->components->ts.u.derived; /* Assume there is no DEFAULT case. */ default_case = NULL; @@ -6487,6 +6913,32 @@ resolve_select_type (gfc_code *code) } } + if (code->expr2) + { + /* Insert assignment for selector variable. */ + new_st = gfc_get_code (); + new_st->op = EXEC_ASSIGN; + new_st->expr1 = gfc_copy_expr (code->expr1); + new_st->expr2 = gfc_copy_expr (code->expr2); + ns->code = new_st; + } + + /* Put SELECT TYPE statement inside a BLOCK. */ + new_st = gfc_get_code (); + new_st->op = code->op; + new_st->expr1 = code->expr1; + new_st->expr2 = code->expr2; + new_st->block = code->block; + if (!ns->code) + ns->code = new_st; + else + ns->code->next = new_st; + code->op = EXEC_BLOCK; + code->expr1 = code->expr2 = NULL; + code->block = NULL; + + code = new_st; + /* Transform to EXEC_SELECT. */ code->op = EXEC_SELECT; gfc_add_component_ref (code->expr1, "$vindex"); @@ -6506,7 +6958,7 @@ resolve_select_type (gfc_code *code) continue; /* Assign temporary to selector. */ sprintf (name, "tmp$%s", c->ts.u.derived->name); - st = gfc_find_symtree (code->expr1->symtree->n.sym->ns->sym_root, name); + st = gfc_find_symtree (ns->sym_root, name); new_st = gfc_get_code (); new_st->op = EXEC_POINTER_ASSIGN; new_st->expr1 = gfc_get_variable_expr (st); @@ -7287,46 +7739,16 @@ resolve_ordinary_assign (gfc_code *code, gfc_namespace *ns) } } - gfc_check_assign (lhs, rhs, 1); - return false; -} - - -/* Check an assignment to a CLASS object (pointer or ordinary assignment). */ - -static void -resolve_class_assign (gfc_code *code) -{ - gfc_code *assign_code = gfc_get_code (); - - if (code->expr2->ts.type != BT_CLASS) + /* F03:7.4.1.2. */ + if (lhs->ts.type == BT_CLASS) { - /* Insert an additional assignment which sets the vindex. */ - assign_code->next = code->next; - code->next = assign_code; - assign_code->op = EXEC_ASSIGN; - assign_code->expr1 = gfc_copy_expr (code->expr1); - gfc_add_component_ref (assign_code->expr1, "$vindex"); - if (code->expr2->ts.type == BT_DERIVED) - /* vindex is constant, determined at compile time. */ - assign_code->expr2 = gfc_int_expr (code->expr2->ts.u.derived->vindex); - else if (code->expr2->ts.type == BT_CLASS) - { - /* vindex must be determined at run time. */ - assign_code->expr2 = gfc_copy_expr (code->expr2); - gfc_add_component_ref (assign_code->expr2, "$vindex"); - } - else if (code->expr2->expr_type == EXPR_NULL) - assign_code->expr2 = gfc_int_expr (0); - else - gcc_unreachable (); + gfc_error ("Variable must not be polymorphic in assignment at %L", + &lhs->where); + return false; } - /* Modify the actual pointer assignment. */ - if (code->expr2->ts.type == BT_CLASS) - code->op = EXEC_ASSIGN; - else - gfc_add_component_ref (code->expr1, "$data"); + gfc_check_assign (lhs, rhs, 1); + return false; } @@ -7400,6 +7822,10 @@ resolve_code (gfc_code *code, gfc_namespace *ns) if (gfc_resolve_expr (code->expr2) == FAILURE) t = FAILURE; + if (code->op == EXEC_ALLOCATE + && gfc_resolve_expr (code->expr3) == FAILURE) + t = FAILURE; + switch (code->op) { case EXEC_NOP: @@ -7452,9 +7878,6 @@ resolve_code (gfc_code *code, gfc_namespace *ns) if (t == FAILURE) break; - if (code->expr1->ts.type == BT_CLASS) - resolve_class_assign (code); - if (resolve_ordinary_assign (code, ns)) { if (code->op == EXEC_COMPCALL) @@ -7462,7 +7885,6 @@ resolve_code (gfc_code *code, gfc_namespace *ns) else goto call; } - break; case EXEC_LABEL_ASSIGN: @@ -7483,11 +7905,7 @@ resolve_code (gfc_code *code, gfc_namespace *ns) if (t == FAILURE) break; - if (code->expr1->ts.type == BT_CLASS) - resolve_class_assign (code); - gfc_check_pointer_assign (code->expr1, code->expr2); - break; case EXEC_ARITHMETIC_IF: @@ -7517,7 +7935,11 @@ resolve_code (gfc_code *code, gfc_namespace *ns) case EXEC_COMPCALL: compcall: - resolve_typebound_call (code); + if (code->expr1->symtree + && code->expr1->symtree->n.sym->ts.type == BT_CLASS) + resolve_class_typebound_call (code); + else + resolve_typebound_call (code); break; case EXEC_CALL_PPC: @@ -8219,7 +8641,8 @@ apply_default_init_local (gfc_symbol *sym) /* For saved variables, we don't want to add an initializer at function entry, so we just add a static initializer. */ - if (sym->attr.save || sym->ns->save_all) + if (sym->attr.save || sym->ns->save_all + || gfc_option.flag_max_stack_var_size == 0) { /* Don't clobber an existing initializer! */ gcc_assert (sym->value == NULL); @@ -8333,9 +8756,8 @@ resolve_fl_variable_derived (gfc_symbol *sym, int no_init_flag) } /* C509. */ - if (!(sym->attr.dummy || sym->attr.allocatable || sym->attr.pointer - || sym->ts.u.derived->components->attr.allocatable - || sym->ts.u.derived->components->attr.pointer)) + /* Assume that use associated symbols were checked in the module ns. */ + if (!sym->attr.class_ok && !sym->attr.use_assoc) { gfc_error ("CLASS variable '%s' at %L must be dummy, allocatable " "or pointer", sym->name, &sym->declared_at); @@ -11724,7 +12146,11 @@ resolve_codes (gfc_namespace *ns) resolve_codes (n); gfc_current_ns = ns; - cs_base = NULL; + + /* Don't clear 'cs_base' if this is the namespace of a BLOCK construct. */ + if (!(ns->proc_name && ns->proc_name->attr.flavor == FL_LABEL)) + cs_base = NULL; + /* Set to an out of range value. */ current_entry_id = -1; diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c index 39285b16fea..c1b39b0d9f1 100644 --- a/gcc/fortran/symbol.c +++ b/gcc/fortran/symbol.c @@ -2030,9 +2030,16 @@ gfc_st_label * gfc_get_st_label (int labelno) { gfc_st_label *lp; + gfc_namespace *ns; + + /* Find the namespace of the scoping unit: + If we're in a BLOCK construct, jump to the parent namespace. */ + ns = gfc_current_ns; + while (ns->proc_name && ns->proc_name->attr.flavor == FL_LABEL) + ns = ns->parent; /* First see if the label is already in this namespace. */ - lp = gfc_current_ns->st_labels; + lp = ns->st_labels; while (lp) { if (lp->value == labelno) @@ -2050,7 +2057,7 @@ gfc_get_st_label (int labelno) lp->defined = ST_LABEL_UNKNOWN; lp->referenced = ST_LABEL_UNKNOWN; - gfc_insert_bbt (&gfc_current_ns->st_labels, lp, compare_st_labels); + gfc_insert_bbt (&ns->st_labels, lp, compare_st_labels); return lp; } @@ -2461,6 +2468,19 @@ ambiguous_symbol (const char *name, gfc_symtree *st) } +/* If we're in a SELECT TYPE block, check if the variable 'st' matches any + selector on the stack. If yes, replace it by the corresponding temporary. */ + +static void +select_type_insert_tmp (gfc_symtree **st) +{ + gfc_select_type_stack *stack = select_type_stack; + for (; stack; stack = stack->prev) + if ((*st)->n.sym == stack->selector) + *st = stack->tmp; +} + + /* Search for a symtree starting in the current namespace, resorting to any parent namespaces if requested by a nonzero parent_flag. Returns nonzero if the name is ambiguous. */ @@ -2479,6 +2499,8 @@ gfc_find_sym_tree (const char *name, gfc_namespace *ns, int parent_flag, st = gfc_find_symtree (ns->sym_root, name); if (st != NULL) { + select_type_insert_tmp (&st); + *result = st; /* Ambiguous generic interfaces are permitted, as long as the specific interfaces are different. */ @@ -2645,12 +2667,6 @@ gfc_get_ha_sym_tree (const char *name, gfc_symtree **result) i = gfc_find_sym_tree (name, gfc_current_ns, 0, &st); - /* Special case: If we're in a SELECT TYPE block, - replace the selector variable by a temporary. */ - if (gfc_current_state () == COMP_SELECT_TYPE - && st && st->n.sym == type_selector) - st = select_type_tmp; - if (st != NULL) { save_symbol_data (st->n.sym); @@ -2732,7 +2748,7 @@ gfc_undo_symbols (void) if (p->gfc_new) { /* Symbol was new. */ - if (p->attr.in_common && p->common_block->head) + if (p->attr.in_common && p->common_block && p->common_block->head) { /* If the symbol was added to any common block, it needs to be removed to stop the resolver looking @@ -4579,9 +4595,12 @@ gfc_type_compatible (gfc_typespec *ts1, gfc_typespec *ts2) if ((ts1->type == BT_DERIVED || ts1->type == BT_CLASS) && (ts2->type == BT_DERIVED || ts2->type == BT_CLASS)) { - if (ts1->type == BT_CLASS) + if (ts1->type == BT_CLASS && ts2->type == BT_DERIVED) return gfc_type_is_extension_of (ts1->u.derived->components->ts.u.derived, ts2->u.derived); + else if (ts1->type == BT_CLASS && ts2->type == BT_CLASS) + return gfc_type_is_extension_of (ts1->u.derived->components->ts.u.derived, + ts2->u.derived->components->ts.u.derived); else if (ts2->type != BT_CLASS) return gfc_compare_derived_types (ts1->u.derived, ts2->u.derived); else diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index e16200010d1..4e94373133a 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -5906,6 +5906,36 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, tmp = gfc_trans_dealloc_allocated (comp); gfc_add_expr_to_block (&fnblock, tmp); } + else if (c->attr.allocatable) + { + /* Allocatable scalar components. */ + comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + + tmp = gfc_deallocate_with_status (comp, NULL_TREE, true, NULL); + gfc_add_expr_to_block (&fnblock, tmp); + + tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp, + build_int_cst (TREE_TYPE (comp), 0)); + gfc_add_expr_to_block (&fnblock, tmp); + } + else if (c->ts.type == BT_CLASS + && c->ts.u.derived->components->attr.allocatable) + { + /* Allocatable scalar CLASS components. */ + comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + + /* Add reference to '$data' component. */ + tmp = c->ts.u.derived->components->backend_decl; + comp = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp), + comp, tmp, NULL_TREE); + + tmp = gfc_deallocate_with_status (comp, NULL_TREE, true, NULL); + gfc_add_expr_to_block (&fnblock, tmp); + + tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp, + build_int_cst (TREE_TYPE (comp), 0)); + gfc_add_expr_to_block (&fnblock, tmp); + } break; case NULLIFY_ALLOC_COMP: @@ -5917,6 +5947,27 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl, decl, cdecl, NULL_TREE); gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node); } + else if (c->attr.allocatable) + { + /* Allocatable scalar components. */ + comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp, + build_int_cst (TREE_TYPE (comp), 0)); + gfc_add_expr_to_block (&fnblock, tmp); + } + else if (c->ts.type == BT_CLASS + && c->ts.u.derived->components->attr.allocatable) + { + /* Allocatable scalar CLASS components. */ + comp = fold_build3 (COMPONENT_REF, ctype, decl, cdecl, NULL_TREE); + /* Add reference to '$data' component. */ + tmp = c->ts.u.derived->components->backend_decl; + comp = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp), + comp, tmp, NULL_TREE); + tmp = fold_build2 (MODIFY_EXPR, void_type_node, comp, + build_int_cst (TREE_TYPE (comp), 0)); + gfc_add_expr_to_block (&fnblock, tmp); + } else if (cmp_has_alloc_comps) { comp = fold_build3 (COMPONENT_REF, ctype, diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c index 5b1952aee4a..1fb3c40f113 100644 --- a/gcc/fortran/trans-common.c +++ b/gcc/fortran/trans-common.c @@ -680,7 +680,6 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv) var_decl = build_decl (s->sym->declared_at.lb->location, VAR_DECL, DECL_NAME (s->field), TREE_TYPE (s->field)); - TREE_PUBLIC (var_decl) = TREE_PUBLIC (decl); TREE_STATIC (var_decl) = TREE_STATIC (decl); TREE_USED (var_decl) = TREE_USED (decl); if (s->sym->attr.use_assoc) @@ -689,7 +688,9 @@ create_common (gfc_common_head *com, segment_info *head, bool saw_equiv) TREE_ADDRESSABLE (var_decl) = 1; /* This is a fake variable just for debugging purposes. */ TREE_ASM_WRITTEN (var_decl) = 1; - + /* Fake variables are not visible from other translation units. */ + TREE_PUBLIC (var_decl) = 0; + /* To preserve identifier names in COMMON, chain to procedure scope unless at top level in a module definition. */ if (com diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index ee38efbe27c..200c3f5654c 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -1187,22 +1187,23 @@ gfc_get_symbol_decl (gfc_symbol * sym) /* 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; } - if (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.alloc_comp) - gfc_defer_symbol_init (sym); - /* This applies a derived type default initializer. */ - else if (sym->ts.type == BT_DERIVED - && sym->attr.save == SAVE_NONE - && !sym->attr.data - && !sym->attr.allocatable - && (sym->value && !sym->ns->proc_name->attr.is_main_program) - && !sym->attr.use_assoc) + /* Remember this variable for allocation/cleanup. */ + if (sym->attr.dimension || sym->attr.allocatable + || (sym->ts.type == BT_CLASS && + (sym->ts.u.derived->components->attr.dimension + || sym->ts.u.derived->components->attr.allocatable)) + || (sym->ts.type == BT_DERIVED && sym->ts.u.derived->attr.alloc_comp) + /* This applies a derived type default initializer. */ + || (sym->ts.type == BT_DERIVED + && sym->attr.save == SAVE_NONE + && !sym->attr.data + && !sym->attr.allocatable + && (sym->value && !sym->ns->proc_name->attr.is_main_program) + && !sym->attr.use_assoc)) gfc_defer_symbol_init (sym); gfc_finish_var_decl (decl, sym); @@ -3054,7 +3055,8 @@ init_intent_out_dt (gfc_symbol * proc_sym, tree body) Allocation and initialization of array variables. Allocation of character string variables. Initialization and possibly repacking of dummy arrays. - Initialization of ASSIGN statement auxiliary variable. */ + Initialization of ASSIGN statement auxiliary variable. + Automatic deallocation. */ tree gfc_trans_deferred_vars (gfc_symbol * proc_sym, tree fnbody) @@ -3182,6 +3184,33 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, tree fnbody) } else if (sym_has_alloc_comp) fnbody = gfc_trans_deferred_array (sym, fnbody); + else if (sym->attr.allocatable + || (sym->ts.type == BT_CLASS + && sym->ts.u.derived->components->attr.allocatable)) + { + /* Automatic deallocatation of allocatable scalars. */ + tree tmp; + gfc_expr *e; + gfc_se se; + stmtblock_t block; + + e = gfc_lval_expr_from_sym (sym); + if (sym->ts.type == BT_CLASS) + gfc_add_component_ref (e, "$data"); + + gfc_init_se (&se, NULL); + se.want_pointer = 1; + gfc_conv_expr (&se, e); + gfc_free_expr (e); + + gfc_start_block (&block); + gfc_add_expr_to_block (&block, fnbody); + + /* Note: Nullifying is not needed. */ + tmp = gfc_deallocate_with_status (se.expr, NULL_TREE, true, NULL); + gfc_add_expr_to_block (&block, tmp); + fnbody = gfc_finish_block (&block); + } else if (sym->ts.type == BT_CHARACTER) { gfc_get_backend_locus (&loc); @@ -3747,8 +3776,12 @@ generate_local_decl (gfc_symbol * sym) else if (warn_unused_variable && sym->attr.dummy && sym->attr.intent == INTENT_OUT) - gfc_warning ("Dummy argument '%s' at %L was declared INTENT(OUT) but was not set", - sym->name, &sym->declared_at); + { + if (!(sym->ts.type == BT_DERIVED + && sym->ts.u.derived->components->initializer)) + gfc_warning ("Dummy argument '%s' at %L was declared INTENT(OUT) " + "but was not set", sym->name, &sym->declared_at); + } /* Specific warning for unused dummy arguments. */ else if (warn_unused_variable && sym->attr.dummy) gfc_warning ("Unused dummy argument '%s' at %L", sym->name, @@ -4363,10 +4396,10 @@ gfc_generate_function_code (gfc_namespace * ns) /* Reset recursion-check variable. */ if ((gfc_option.rtcheck & GFC_RTCHECK_RECURSION) && !is_recursive) - { - gfc_add_modify (&block, recurcheckvar, boolean_false_node); - recurcheckvar = NULL; - } + { + gfc_add_modify (&block, recurcheckvar, boolean_false_node); + recurcheckvar = NULL; + } if (result == NULL_TREE) { diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index eb741f8231f..5a45f4f6368 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -1519,15 +1519,142 @@ get_proc_ptr_comp (gfc_expr *e) e2 = gfc_copy_expr (e); e2->expr_type = EXPR_VARIABLE; gfc_conv_expr (&comp_se, e2); + gfc_free_expr (e2); return build_fold_addr_expr_loc (input_location, comp_se.expr); } +/* Select a class typebound procedure at runtime. */ +static void +select_class_proc (gfc_se *se, gfc_class_esym_list *elist, + tree declared, gfc_expr *expr) +{ + tree end_label; + tree label; + tree tmp; + tree vindex; + stmtblock_t body; + gfc_class_esym_list *next_elist, *tmp_elist; + gfc_se tmpse; + + /* Convert the vindex expression. */ + gfc_init_se (&tmpse, NULL); + gfc_conv_expr (&tmpse, elist->vindex); + gfc_add_block_to_block (&se->pre, &tmpse.pre); + vindex = gfc_evaluate_now (tmpse.expr, &se->pre); + gfc_add_block_to_block (&se->post, &tmpse.post); + + /* Fix the function type to be that of the declared type method. */ + declared = gfc_create_var (TREE_TYPE (declared), "method"); + + end_label = gfc_build_label_decl (NULL_TREE); + + gfc_init_block (&body); + + /* Go through the list of extensions. */ + for (; elist; elist = next_elist) + { + /* This case has already been added. */ + if (elist->derived == NULL) + goto free_elist; + + /* Run through the chain picking up all the cases that call the + same procedure. */ + tmp_elist = elist; + for (; elist; elist = elist->next) + { + tree cval; + + if (elist->esym != tmp_elist->esym) + continue; + + cval = build_int_cst (TREE_TYPE (vindex), + elist->derived->vindex); + /* Build a label for the vindex value. */ + label = gfc_build_label_decl (NULL_TREE); + tmp = fold_build3 (CASE_LABEL_EXPR, void_type_node, + cval, NULL_TREE, label); + gfc_add_expr_to_block (&body, tmp); + + /* Null the reference the derived type so that this case is + not used again. */ + elist->derived = NULL; + } + + elist = tmp_elist; + + /* Get a pointer to the procedure, */ + tmp = gfc_get_symbol_decl (elist->esym); + if (!POINTER_TYPE_P (TREE_TYPE (tmp))) + { + gcc_assert (TREE_CODE (tmp) == FUNCTION_DECL); + tmp = gfc_build_addr_expr (NULL_TREE, tmp); + } + + /* Assign the pointer to the appropriate procedure. */ + gfc_add_modify (&body, declared, + fold_convert (TREE_TYPE (declared), tmp)); + + /* Break to the end of the construct. */ + tmp = build1_v (GOTO_EXPR, end_label); + gfc_add_expr_to_block (&body, tmp); + + /* Free the elists as we go; freeing them in gfc_free_expr causes + segfaults because it occurs too early and too often. */ + free_elist: + next_elist = elist->next; + if (elist->vindex) + gfc_free_expr (elist->vindex); + gfc_free (elist); + elist = NULL; + } + + /* Default is an error. */ + label = gfc_build_label_decl (NULL_TREE); + tmp = fold_build3 (CASE_LABEL_EXPR, void_type_node, + NULL_TREE, NULL_TREE, label); + gfc_add_expr_to_block (&body, tmp); + tmp = gfc_trans_runtime_error (true, &expr->where, + "internal error: bad vindex in dynamic dispatch"); + gfc_add_expr_to_block (&body, tmp); + + /* Write the switch expression. */ + tmp = gfc_finish_block (&body); + tmp = build3_v (SWITCH_EXPR, vindex, tmp, NULL_TREE); + gfc_add_expr_to_block (&se->pre, tmp); + + tmp = build1_v (LABEL_EXPR, end_label); + gfc_add_expr_to_block (&se->pre, tmp); + + se->expr = declared; + return; +} + + static void conv_function_val (gfc_se * se, gfc_symbol * sym, gfc_expr * expr) { tree tmp; + if (expr && expr->symtree + && expr->value.function.class_esym) + { + if (!sym->backend_decl) + sym->backend_decl = gfc_get_extern_function_decl (sym); + + tmp = sym->backend_decl; + + if (!POINTER_TYPE_P (TREE_TYPE (tmp))) + { + gcc_assert (TREE_CODE (tmp) == FUNCTION_DECL); + tmp = gfc_build_addr_expr (NULL_TREE, tmp); + } + + select_class_proc (se, expr->value.function.class_esym, + tmp, expr); + return; + } + if (gfc_is_proc_ptr_comp (expr, NULL)) tmp = get_proc_ptr_comp (expr); else if (sym->attr.dummy) @@ -2651,6 +2778,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, { tree data; tree vindex; + tree size; /* The derived type needs to be converted to a temporary CLASS object. */ @@ -2664,13 +2792,20 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, var, tmp, NULL_TREE); tmp = fsym->ts.u.derived->components->next->backend_decl; vindex = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp), + var, tmp, NULL_TREE); + tmp = fsym->ts.u.derived->components->next->next->backend_decl; + size = fold_build3 (COMPONENT_REF, TREE_TYPE (tmp), var, tmp, NULL_TREE); /* Set the vindex. */ - tmp = build_int_cst (TREE_TYPE (vindex), - e->ts.u.derived->vindex); + tmp = build_int_cst (TREE_TYPE (vindex), e->ts.u.derived->vindex); gfc_add_modify (&parmse.pre, vindex, tmp); + /* Set the size. */ + tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&e->ts)); + gfc_add_modify (&parmse.pre, size, + fold_convert (TREE_TYPE (size), tmp)); + /* Now set the data field. */ argss = gfc_walk_expr (e); if (argss == gfc_ss_terminator) @@ -2735,8 +2870,11 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, through arg->name. */ conv_arglist_function (&parmse, arg->expr, arg->name); else if ((e->expr_type == EXPR_FUNCTION) - && e->symtree->n.sym->attr.pointer - && fsym && fsym->attr.target) + && ((e->value.function.esym + && e->value.function.esym->result->attr.pointer) + || (!e->value.function.esym + && e->symtree->n.sym->attr.pointer)) + && fsym && fsym->attr.target) { gfc_conv_expr (&parmse, e); parmse.expr = gfc_build_addr_expr (NULL_TREE, parmse.expr); @@ -2754,6 +2892,37 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, else { gfc_conv_expr_reference (&parmse, e); + + /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is + allocated on entry, it must be deallocated. */ + if (fsym && fsym->attr.allocatable + && fsym->attr.intent == INTENT_OUT) + { + stmtblock_t block; + + gfc_init_block (&block); + tmp = gfc_deallocate_with_status (parmse.expr, NULL_TREE, + true, NULL); + gfc_add_expr_to_block (&block, tmp); + tmp = fold_build2 (MODIFY_EXPR, void_type_node, + parmse.expr, null_pointer_node); + gfc_add_expr_to_block (&block, tmp); + + if (fsym->attr.optional + && e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.optional) + { + tmp = fold_build3 (COND_EXPR, void_type_node, + gfc_conv_expr_present (e->symtree->n.sym), + gfc_finish_block (&block), + build_empty_stmt (input_location)); + } + else + tmp = gfc_finish_block (&block); + + gfc_add_expr_to_block (&se->pre, tmp); + } + if (fsym && e->expr_type != EXPR_NULL && ((fsym->attr.pointer && fsym->attr.flavor != FL_PROCEDURE) @@ -2761,7 +2930,8 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, && !(e->expr_type == EXPR_VARIABLE && e->symtree->n.sym->attr.dummy)) || (e->expr_type == EXPR_VARIABLE - && gfc_is_proc_ptr_comp (e, NULL)))) + && gfc_is_proc_ptr_comp (e, NULL)) + || fsym->attr.allocatable)) { /* Scalar pointer dummy args require an extra level of indirection. The null pointer already contains @@ -2797,17 +2967,22 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_conv_array_parameter (&parmse, e, argss, f, fsym, sym->name, NULL); - /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is - allocated on entry, it must be deallocated. */ - if (fsym && fsym->attr.allocatable - && fsym->attr.intent == INTENT_OUT) - { - tmp = build_fold_indirect_ref_loc (input_location, - parmse.expr); - tmp = gfc_trans_dealloc_allocated (tmp); - gfc_add_expr_to_block (&se->pre, tmp); - } - + /* If an ALLOCATABLE dummy argument has INTENT(OUT) and is + allocated on entry, it must be deallocated. */ + if (fsym && fsym->attr.allocatable + && fsym->attr.intent == INTENT_OUT) + { + tmp = build_fold_indirect_ref_loc (input_location, + parmse.expr); + tmp = gfc_trans_dealloc_allocated (tmp); + if (fsym->attr.optional + && e->expr_type == EXPR_VARIABLE + && e->symtree->n.sym->attr.optional) + tmp = fold_build3 (COND_EXPR, void_type_node, + gfc_conv_expr_present (e->symtree->n.sym), + tmp, build_empty_stmt (input_location)); + gfc_add_expr_to_block (&se->pre, tmp); + } } } @@ -2819,9 +2994,23 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, if (e && (fsym == NULL || fsym->attr.optional)) { /* If an optional argument is itself an optional dummy argument, - check its presence and substitute a null if absent. */ + check its presence and substitute a null if absent. This is + only needed when passing an array to an elemental procedure + as then array elements are accessed - or no NULL pointer is + allowed and a "1" or "0" should be passed if not present. + When passing a non-array-descriptor full array to a + non-array-descriptor dummy, no check is needed. For + array-descriptor actual to array-descriptor dummy, see + PR 41911 for why a check has to be inserted. + fsym == NULL is checked as intrinsics required the descriptor + but do not always set fsym. */ if (e->expr_type == EXPR_VARIABLE - && e->symtree->n.sym->attr.optional) + && e->symtree->n.sym->attr.optional + && ((e->rank > 0 && sym->attr.elemental) + || e->representation.length || e->ts.type == BT_CHARACTER + || (e->rank > 0 + && (fsym == NULL || fsym->as->type == AS_ASSUMED_SHAPE + || fsym->as->type == AS_DEFERRED)))) gfc_conv_missing_dummy (&parmse, e, fsym ? fsym->ts : e->ts, e->representation.length); } @@ -3015,7 +3204,7 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, cl.backend_decl = formal->sym->ts.u.cl->backend_decl; } } - else + else { tree tmp; @@ -4233,8 +4422,12 @@ gfc_conv_expr_reference (gfc_se * se, gfc_expr * expr) } if (expr->expr_type == EXPR_FUNCTION - && expr->symtree->n.sym->attr.pointer - && !expr->symtree->n.sym->attr.dimension) + && ((expr->value.function.esym + && expr->value.function.esym->result->attr.pointer + && !expr->value.function.esym->result->attr.dimension) + || (!expr->value.function.esym + && expr->symtree->n.sym->attr.pointer + && !expr->symtree->n.sym->attr.dimension))) { se->want_pointer = 1; gfc_conv_expr (se, expr); @@ -4525,12 +4718,11 @@ gfc_trans_scalar_assign (gfc_se * lse, gfc_se * rse, gfc_typespec ts, gfc_add_expr_to_block (&block, tmp); } } - else if (ts.type == BT_DERIVED) + else if (ts.type == BT_DERIVED || ts.type == BT_CLASS) { gfc_add_block_to_block (&block, &lse->pre); gfc_add_block_to_block (&block, &rse->pre); - tmp = gfc_evaluate_now (rse->expr, &block); - tmp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lse->expr), tmp); + tmp = fold_build1 (VIEW_CONVERT_EXPR, TREE_TYPE (lse->expr), rse->expr); gfc_add_modify (&block, lse->expr, tmp); } else @@ -5137,3 +5329,75 @@ gfc_trans_assign (gfc_code * code) { return gfc_trans_assignment (code->expr1, code->expr2, false); } + + +/* Translate an assignment to a CLASS object + (pointer or ordinary assignment). */ + +tree +gfc_trans_class_assign (gfc_code *code) +{ + stmtblock_t block; + tree tmp; + + gfc_start_block (&block); + + if (code->expr2->ts.type != BT_CLASS) + { + /* Insert an additional assignment which sets the '$vindex' field. */ + gfc_expr *lhs,*rhs; + lhs = gfc_copy_expr (code->expr1); + gfc_add_component_ref (lhs, "$vindex"); + if (code->expr2->ts.type == BT_DERIVED) + /* vindex is constant, determined at compile time. */ + rhs = gfc_int_expr (code->expr2->ts.u.derived->vindex); + else if (code->expr2->expr_type == EXPR_NULL) + rhs = gfc_int_expr (0); + else + gcc_unreachable (); + tmp = gfc_trans_assignment (lhs, rhs, false); + gfc_add_expr_to_block (&block, tmp); + + /* Insert another assignment which sets the '$size' field. */ + lhs = gfc_copy_expr (code->expr1); + gfc_add_component_ref (lhs, "$size"); + if (code->expr2->ts.type == BT_DERIVED) + { + /* Size is fixed at compile time. */ + gfc_se lse; + gfc_init_se (&lse, NULL); + gfc_conv_expr (&lse, lhs); + tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr2->ts)); + gfc_add_modify (&block, lse.expr, + fold_convert (TREE_TYPE (lse.expr), tmp)); + } + else if (code->expr2->expr_type == EXPR_NULL) + { + rhs = gfc_int_expr (0); + tmp = gfc_trans_assignment (lhs, rhs, false); + gfc_add_expr_to_block (&block, tmp); + } + else + gcc_unreachable (); + + gfc_free_expr (lhs); + gfc_free_expr (rhs); + } + + /* Do the actual CLASS assignment. */ + if (code->expr2->ts.type == BT_CLASS) + code->op = EXEC_ASSIGN; + else + gfc_add_component_ref (code->expr1, "$data"); + + if (code->op == EXEC_ASSIGN) + tmp = gfc_trans_assign (code); + else if (code->op == EXEC_POINTER_ASSIGN) + tmp = gfc_trans_pointer_assign (code); + else + gcc_unreachable(); + + gfc_add_expr_to_block (&block, tmp); + + return gfc_finish_block (&block); +} diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index 1e7b35f5c17..c3d7dfbab3c 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -4490,6 +4490,8 @@ gfc_conv_intrinsic_transfer (gfc_se * se, gfc_expr * expr) scalar_transfer: extent = fold_build2 (MIN_EXPR, gfc_array_index_type, dest_word_len, source_bytes); + extent = fold_build2 (MAX_EXPR, gfc_array_index_type, + extent, gfc_index_zero_node); if (expr->ts.type == BT_CHARACTER) { diff --git a/gcc/fortran/trans-openmp.c b/gcc/fortran/trans-openmp.c index 56534ccdd38..4d461cfa488 100644 --- a/gcc/fortran/trans-openmp.c +++ b/gcc/fortran/trans-openmp.c @@ -1641,11 +1641,6 @@ gfc_trans_omp_workshare (gfc_code *code, gfc_omp_clauses *clauses) if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) { - if (TREE_CODE (res) == STATEMENT_LIST) - tree_annotate_all_with_location (&res, input_location); - else - SET_EXPR_LOCATION (res, input_location); - if (prev_singleunit) { if (ompws_flags & OMPWS_CURR_SINGLEUNIT) diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 9d3197d11bc..9b2a6230853 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -159,31 +159,15 @@ gfc_trans_goto (gfc_code * code) assigned_goto = GFC_DECL_ASSIGN_ADDR (se.expr); - code = code->block; - if (code == NULL) - { - target = fold_build1 (GOTO_EXPR, void_type_node, assigned_goto); - gfc_add_expr_to_block (&se.pre, target); - return gfc_finish_block (&se.pre); - } - - /* Check the label list. */ - do - { - target = gfc_get_label_decl (code->label1); - tmp = gfc_build_addr_expr (pvoid_type_node, target); - tmp = fold_build2 (EQ_EXPR, boolean_type_node, tmp, assigned_goto); - tmp = build3_v (COND_EXPR, tmp, - fold_build1 (GOTO_EXPR, void_type_node, target), - build_empty_stmt (input_location)); - gfc_add_expr_to_block (&se.pre, tmp); - code = code->block; - } - while (code != NULL); - gfc_trans_runtime_check (true, false, boolean_true_node, &se.pre, &loc, - "Assigned label is not in the list"); - - return gfc_finish_block (&se.pre); + /* We're going to ignore a label list. It does not really change the + statement's semantics (because it is just a further restriction on + what's legal code); before, we were comparing label addresses here, but + that's a very fragile business and may break with optimization. So + just ignore it. */ + + target = fold_build1 (GOTO_EXPR, void_type_node, assigned_goto); + gfc_add_expr_to_block (&se.pre, target); + return gfc_finish_block (&se.pre); } @@ -3992,19 +3976,20 @@ tree gfc_trans_allocate (gfc_code * code) { gfc_alloc *al; - gfc_expr *expr, *init_e, *rhs; + gfc_expr *expr, *init_e; gfc_se se; tree tmp; tree parm; tree stat; tree pstat; tree error_label; + tree memsz; stmtblock_t block; if (!code->ext.alloc.list) return NULL_TREE; - pstat = stat = error_label = tmp = NULL_TREE; + pstat = stat = error_label = tmp = memsz = NULL_TREE; gfc_start_block (&block); @@ -4022,7 +4007,10 @@ gfc_trans_allocate (gfc_code * code) for (al = code->ext.alloc.list; al != NULL; al = al->next) { - expr = al->expr; + expr = gfc_copy_expr (al->expr); + + if (expr->ts.type == BT_CLASS) + gfc_add_component_ref (expr, "$data"); gfc_init_se (&se, NULL); gfc_start_block (&se.pre); @@ -4038,25 +4026,26 @@ gfc_trans_allocate (gfc_code * code) /* Determine allocate size. */ if (code->expr3 && code->expr3->ts.type == BT_CLASS) { - gfc_typespec *ts; - /* TODO: Size must be determined at run time, since it must equal - the size of the dynamic type of SOURCE, not the declared type. */ - gfc_warning ("Dynamic size allocation at %L not supported yet, " - "using size of declared type", &code->loc); - ts = &code->expr3->ts.u.derived->components->ts; - tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (ts)); + gfc_expr *sz; + gfc_se se_sz; + sz = gfc_copy_expr (code->expr3); + gfc_add_component_ref (sz, "$size"); + gfc_init_se (&se_sz, NULL); + gfc_conv_expr (&se_sz, sz); + gfc_free_expr (sz); + memsz = se_sz.expr; } else if (code->expr3 && code->expr3->ts.type != BT_CLASS) - tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr3->ts)); + memsz = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->expr3->ts)); else if (code->ext.alloc.ts.type != BT_UNKNOWN) - tmp = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->ext.alloc.ts)); + memsz = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&code->ext.alloc.ts)); else - tmp = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (se.expr))); + memsz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (se.expr))); - if (expr->ts.type == BT_CHARACTER && tmp == NULL_TREE) - tmp = se.string_length; + if (expr->ts.type == BT_CHARACTER && memsz == NULL_TREE) + memsz = se.string_length; - tmp = gfc_allocate_with_status (&se.pre, tmp, pstat); + tmp = gfc_allocate_with_status (&se.pre, memsz, pstat); tmp = fold_build2 (MODIFY_EXPR, void_type_node, se.expr, fold_convert (TREE_TYPE (se.expr), tmp)); gfc_add_expr_to_block (&se.pre, tmp); @@ -4086,17 +4075,91 @@ gfc_trans_allocate (gfc_code * code) /* Initialization via SOURCE block. */ if (code->expr3) { - rhs = gfc_copy_expr (code->expr3); - if (rhs->ts.type == BT_CLASS) - gfc_add_component_ref (rhs, "$data"); - tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr), rhs, false); + gfc_expr *rhs = gfc_copy_expr (code->expr3); + if (al->expr->ts.type == BT_CLASS) + { + gfc_se dst,src; + if (rhs->ts.type == BT_CLASS) + gfc_add_component_ref (rhs, "$data"); + gfc_init_se (&dst, NULL); + gfc_init_se (&src, NULL); + gfc_conv_expr (&dst, expr); + gfc_conv_expr (&src, rhs); + gfc_add_block_to_block (&block, &src.pre); + tmp = gfc_build_memcpy_call (dst.expr, src.expr, memsz); + } + else + tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr), + rhs, false); + gfc_free_expr (rhs); + gfc_add_expr_to_block (&block, tmp); + } + /* Default initializer for CLASS variables. */ + else if (al->expr->ts.type == BT_CLASS + && code->ext.alloc.ts.type == BT_DERIVED + && (init_e = gfc_default_initializer (&code->ext.alloc.ts))) + { + gfc_se dst,src; + gfc_init_se (&dst, NULL); + gfc_init_se (&src, NULL); + gfc_conv_expr (&dst, expr); + gfc_conv_expr (&src, init_e); + gfc_add_block_to_block (&block, &src.pre); + tmp = gfc_build_memcpy_call (dst.expr, src.expr, memsz); gfc_add_expr_to_block (&block, tmp); } /* Add default initializer for those derived types that need them. */ - else if (expr->ts.type == BT_DERIVED && (init_e = gfc_default_initializer (&expr->ts))) + else if (expr->ts.type == BT_DERIVED + && (init_e = gfc_default_initializer (&expr->ts))) + { + tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr), + init_e, true); + gfc_add_expr_to_block (&block, tmp); + } + + /* Allocation of CLASS entities. */ + gfc_free_expr (expr); + expr = al->expr; + if (expr->ts.type == BT_CLASS) { - tmp = gfc_trans_assignment (gfc_expr_to_initialize (expr), init_e, true); + gfc_expr *lhs,*rhs; + gfc_se lse; + /* Initialize VINDEX for CLASS objects. */ + lhs = gfc_expr_to_initialize (expr); + gfc_add_component_ref (lhs, "$vindex"); + if (code->expr3 && code->expr3->ts.type == BT_CLASS) + { + /* vindex must be determined at run time. */ + rhs = gfc_copy_expr (code->expr3); + gfc_add_component_ref (rhs, "$vindex"); + } + else + { + /* vindex is fixed at compile time. */ + int vindex; + if (code->expr3) + vindex = code->expr3->ts.u.derived->vindex; + else if (code->ext.alloc.ts.type == BT_DERIVED) + vindex = code->ext.alloc.ts.u.derived->vindex; + else if (expr->ts.type == BT_CLASS) + vindex = expr->ts.u.derived->components->ts.u.derived->vindex; + else + vindex = expr->ts.u.derived->vindex; + rhs = gfc_int_expr (vindex); + } + tmp = gfc_trans_assignment (lhs, rhs, false); + gfc_free_expr (lhs); + gfc_free_expr (rhs); gfc_add_expr_to_block (&block, tmp); + + /* Initialize SIZE for CLASS objects. */ + lhs = gfc_expr_to_initialize (expr); + gfc_add_component_ref (lhs, "$size"); + gfc_init_se (&lse, NULL); + gfc_conv_expr (&lse, lhs); + gfc_add_modify (&block, lse.expr, + fold_convert (TREE_TYPE (lse.expr), memsz)); + gfc_free_expr (lhs); } } diff --git a/gcc/fortran/trans-stmt.h b/gcc/fortran/trans-stmt.h index 0b8461c4e15..e6faacd0022 100644 --- a/gcc/fortran/trans-stmt.h +++ b/gcc/fortran/trans-stmt.h @@ -29,6 +29,7 @@ tree gfc_trans_code (gfc_code *); tree gfc_trans_assign (gfc_code *); tree gfc_trans_pointer_assign (gfc_code *); tree gfc_trans_init_assign (gfc_code *); +tree gfc_trans_class_assign (gfc_code *code); /* trans-stmt.c */ tree gfc_trans_cycle (gfc_code *); diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index 09b424c378f..42d22388105 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -1079,7 +1079,10 @@ gfc_trans_code (gfc_code * code) break; case EXEC_ASSIGN: - res = gfc_trans_assign (code); + if (code->expr1->ts.type == BT_CLASS) + res = gfc_trans_class_assign (code); + else + res = gfc_trans_assign (code); break; case EXEC_LABEL_ASSIGN: @@ -1087,7 +1090,10 @@ gfc_trans_code (gfc_code * code) break; case EXEC_POINTER_ASSIGN: - res = gfc_trans_pointer_assign (code); + if (code->expr1->ts.type == BT_CLASS) + res = gfc_trans_class_assign (code); + else + res = gfc_trans_pointer_assign (code); break; case EXEC_INIT_ASSIGN: @@ -1275,9 +1281,7 @@ gfc_trans_code (gfc_code * code) if (res != NULL_TREE && ! IS_EMPTY_STMT (res)) { - if (TREE_CODE (res) == STATEMENT_LIST) - tree_annotate_all_with_location (&res, input_location); - else + if (TREE_CODE (res) != STATEMENT_LIST) SET_EXPR_LOCATION (res, input_location); /* Add the new statement to the block. */ diff --git a/gcc/fwprop.c b/gcc/fwprop.c index d3ed74298c0..75a354ea54d 100644 --- a/gcc/fwprop.c +++ b/gcc/fwprop.c @@ -375,11 +375,12 @@ canonicalize_address (rtx x) static bool should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode, - bool speed) + addr_space_t as, bool speed) { int gain; - if (rtx_equal_p (old_rtx, new_rtx) || !memory_address_p (mode, new_rtx)) + if (rtx_equal_p (old_rtx, new_rtx) + || !memory_address_addr_space_p (mode, new_rtx, as)) return false; /* Copy propagation is always ok. */ @@ -387,7 +388,8 @@ should_replace_address (rtx old_rtx, rtx new_rtx, enum machine_mode mode, return true; /* Prefer the new address if it is less expensive. */ - gain = address_cost (old_rtx, mode, speed) - address_cost (new_rtx, mode, speed); + gain = (address_cost (old_rtx, mode, as, speed) + - address_cost (new_rtx, mode, as, speed)); /* If the addresses have equivalent cost, prefer the new address if it has the highest `rtx_cost'. That has the potential of @@ -555,6 +557,7 @@ propagate_rtx_1 (rtx *px, rtx old_rtx, rtx new_rtx, int flags) /* Copy propagations are always ok. Otherwise check the costs. */ if (!(REG_P (old_rtx) && REG_P (new_rtx)) && !should_replace_address (op0, new_op0, GET_MODE (x), + MEM_ADDR_SPACE (x), flags & PR_OPTIMIZE_FOR_SPEED)) return true; diff --git a/gcc/gcc-plugin.h b/gcc/gcc-plugin.h index 1792c0393a2..2e36f486262 100644 --- a/gcc/gcc-plugin.h +++ b/gcc/gcc-plugin.h @@ -43,6 +43,7 @@ enum plugin_event PLUGIN_REGISTER_GGC_CACHES, /* Register an extra GGC cache table. */ PLUGIN_ATTRIBUTES, /* Called during attribute registration. */ PLUGIN_START_UNIT, /* Called before processing a translation unit. */ + PLUGIN_PRAGMAS, /* Called during pragma registration. */ PLUGIN_EVENT_LAST /* Dummy event used for indexing callback array. */ }; diff --git a/gcc/gcc.c b/gcc/gcc.c index a9ed7e21696..6bc8e150a67 100644 --- a/gcc/gcc.c +++ b/gcc/gcc.c @@ -684,9 +684,15 @@ proper position among the other output files. */ #endif /* config.h can define SWITCHES_NEED_SPACES to control which options - require spaces between the option and the argument. */ + require spaces between the option and the argument. + + We define SWITCHES_NEED_SPACES to include "o" by default. This + causes "-ofoo.o" to be split into "-o foo.o" during the initial + processing of the command-line, before being seen by the specs + machinery. This makes sure we record "foo.o" as the temporary file + to be deleted in the case of error, rather than "-ofoo.o". */ #ifndef SWITCHES_NEED_SPACES -#define SWITCHES_NEED_SPACES "" +#define SWITCHES_NEED_SPACES "o" #endif /* config.h can define ENDFILE_SPEC to override the default crtn files. */ @@ -764,10 +770,24 @@ proper position among the other output files. */ /* We want %{T*} after %{L*} and %D so that it can be used to specify linker scripts which exist in user specified directories, or in standard directories. */ +/* We pass any -flto and -fwhopr flags on to the linker, which is expected + to understand them. In practice, this means it had better be collect2. */ #ifndef LINK_COMMAND_SPEC #define LINK_COMMAND_SPEC "\ %{!fsyntax-only:%{!c:%{!M:%{!MM:%{!E:%{!S:\ - %(linker) %l " LINK_PIE_SPEC "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\ + %(linker) \ + %{fuse-linker-plugin: \ + -plugin %(linker_plugin_file) \ + -plugin-opt=%(lto_wrapper) \ + -plugin-opt=%(lto_gcc) \ + %{static|static-libgcc:-plugin-opt=-pass-through=%(lto_libgcc)} \ + %{static:-plugin-opt=-pass-through=-lc} \ + %{O*:-plugin-opt=-O%*} \ + %{w:-plugin-opt=-w} \ + %{f*:-plugin-opt=-f%*} \ + } \ + %{flto} %{fwhopr} %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*} %(mfwrap) %(link_libgcc) %o\ %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\ @@ -815,6 +835,10 @@ static const char *endfile_spec = ENDFILE_SPEC; static const char *startfile_spec = STARTFILE_SPEC; static const char *switches_need_spaces = SWITCHES_NEED_SPACES; static const char *linker_name_spec = LINKER_NAME; +static const char *linker_plugin_file_spec = ""; +static const char *lto_wrapper_spec = ""; +static const char *lto_gcc_spec = ""; +static const char *lto_libgcc_spec = ""; static const char *link_command_spec = LINK_COMMAND_SPEC; static const char *link_libgcc_spec = LINK_LIBGCC_SPEC; static const char *startfile_prefix_spec = STARTFILE_PREFIX_SPEC; @@ -891,11 +915,15 @@ static const char *asm_options = static const char *invoke_as = #ifdef AS_NEEDS_DASH_FOR_PIPED_INPUT -"%{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\ - %{!S:-o %|.s |\n as %(asm_options) %|.s %A }"; +"%{!fwpa:\ + %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\ + %{!S:-o %|.s |\n as %(asm_options) %|.s %A }\ + }"; #else -"%{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\ - %{!S:-o %|.s |\n as %(asm_options) %m.s %A }"; +"%{!fwpa:\ + %{fcompare-debug=*|fdump-final-insns=*:%:compare-debug-dump-opt()}\ + %{!S:-o %|.s |\n as %(asm_options) %m.s %A }\ + }"; #endif /* Some compilers have limits on line lengths, and the multilib_select @@ -962,7 +990,7 @@ static struct user_specs *user_specs_head, *user_specs_tail; #ifdef HAVE_TARGET_EXECUTABLE_SUFFIX /* This defines which switches stop a full compilation. */ #define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \ - ((CHAR) == 'c' || (CHAR) == 'S') + ((CHAR) == 'c' || (CHAR) == 'S' || (CHAR) == 'E') #ifndef SWITCH_CURTAILS_COMPILATION #define SWITCH_CURTAILS_COMPILATION(CHAR) \ @@ -1653,6 +1681,10 @@ static struct spec_list static_specs[] = INIT_STATIC_SPEC ("multilib_exclusions", &multilib_exclusions), INIT_STATIC_SPEC ("multilib_options", &multilib_options), INIT_STATIC_SPEC ("linker", &linker_name_spec), + INIT_STATIC_SPEC ("linker_plugin_file", &linker_plugin_file_spec), + INIT_STATIC_SPEC ("lto_wrapper", <o_wrapper_spec), + INIT_STATIC_SPEC ("lto_gcc", <o_gcc_spec), + INIT_STATIC_SPEC ("lto_libgcc", <o_libgcc_spec), INIT_STATIC_SPEC ("link_libgcc", &link_libgcc_spec), INIT_STATIC_SPEC ("md_exec_prefix", &md_exec_prefix), INIT_STATIC_SPEC ("md_startfile_prefix", &md_startfile_prefix), @@ -1974,7 +2006,7 @@ static int argbuf_index; static int have_o_argbuf_index = 0; -/* Were the options -c or -S passed. */ +/* Were the options -c, -S or -E passed. */ static int have_c = 0; /* Was the option -o passed. */ @@ -4116,6 +4148,7 @@ process_command (int argc, const char **argv) case 'S': case 'c': + case 'E': if (p[1] == 0) { have_c = 1; @@ -4131,7 +4164,7 @@ process_command (int argc, const char **argv) { int skip; - /* Forward scan, just in case -S or -c is specified + /* Forward scan, just in case -S, -E or -c is specified after -o. */ int j = i + 1; if (p[1] == 0) @@ -4162,7 +4195,10 @@ process_command (int argc, const char **argv) argv[i] = convert_filename (argv[i], ! have_c, 0); #endif /* Save the output name in case -save-temps=obj was used. */ - save_temps_prefix = xstrdup ((p[1] == 0) ? argv[i + 1] : argv[i] + 1); + if ((p[1] == 0) && argv[i + 1]) + save_temps_prefix = xstrdup(argv[i + 1]); + else + save_temps_prefix = xstrdup(argv[i] + 1); goto normal_switch; default: @@ -4532,20 +4568,32 @@ process_command (int argc, const char **argv) } else { + const char *p = strchr (argv[i], '@'); + char *fname; #ifdef HAVE_TARGET_OBJECT_SUFFIX argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK)); #endif + if (!p) + fname = xstrdup (argv[i]); + else + { + fname = (char *)xmalloc (p - argv[i] + 1); + memcpy (fname, argv[i], p - argv[i]); + fname[p - argv[i]] = '\0'; + } + + if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0) + { + perror_with_name (fname); + error_count++; + } + else + { + infiles[n_infiles].language = spec_lang; + infiles[n_infiles++].name = argv[i]; + } - if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0) - { - perror_with_name (argv[i]); - error_count++; - } - else - { - infiles[n_infiles].language = spec_lang; - infiles[n_infiles++].name = argv[i]; - } + free (fname); } } @@ -4608,11 +4656,6 @@ set_collect_gcc_options (void) if ((switches[i].live_cond & SWITCH_IGNORE) != 0) continue; - /* Don't use -fwhole-program when compiling the init and fini routines, - since we'd wrongly assume that the routines aren't needed. */ - if (strcmp (switches[i].part1, "fwhole-program") == 0) - continue; - obstack_grow (&collect_obstack, "'-", 2); q = switches[i].part1; while ((p = strchr (q, '\''))) @@ -6834,14 +6877,6 @@ main (int argc, char **argv) multilib_defaults = XOBFINISH (&multilib_obstack, const char *); } - /* Set up to remember the pathname of gcc and any options - needed for collect. We use argv[0] instead of programname because - we need the complete pathname. */ - obstack_init (&collect_obstack); - obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); - obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1); - xputenv (XOBFINISH (&collect_obstack, char *)); - #ifdef INIT_ENVIRONMENT /* Set up any other necessary machine specific environment variables. */ xputenv (INIT_ENVIRONMENT); @@ -7055,6 +7090,27 @@ main (int argc, char **argv) the subdirectory based on the options. */ set_multilib_dir (); + /* Set up to remember the pathname of gcc and any options + needed for collect. We use argv[0] instead of programname because + we need the complete pathname. */ + obstack_init (&collect_obstack); + obstack_grow (&collect_obstack, "COLLECT_GCC=", sizeof ("COLLECT_GCC=") - 1); + obstack_grow (&collect_obstack, argv[0], strlen (argv[0]) + 1); + xputenv (XOBFINISH (&collect_obstack, char *)); + + /* Set up to remember the pathname of the lto wrapper. */ + + lto_wrapper_spec = find_a_file (&exec_prefixes, "lto-wrapper", X_OK, false); + if (lto_wrapper_spec) + { + obstack_init (&collect_obstack); + obstack_grow (&collect_obstack, "COLLECT_LTO_WRAPPER=", + sizeof ("COLLECT_LTO_WRAPPER=") - 1); + obstack_grow (&collect_obstack, lto_wrapper_spec, + strlen (lto_wrapper_spec) + 1); + xputenv (XOBFINISH (&collect_obstack, char *)); + } + /* Warn about any switches that no pass was interested in. */ for (i = 0; (int) i < n_switches; i++) @@ -7267,7 +7323,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" } if (!combine_inputs && have_c && have_o && lang_n_infiles > 1) - fatal ("cannot specify -o with -c or -S with multiple files"); + fatal ("cannot specify -o with -c, -S or -E with multiple files"); if (combine_flag && save_temps_flag) { @@ -7475,6 +7531,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (num_linker_inputs > 0 && error_count == 0 && print_subprocess_help < 2) { int tmp = execution_count; + const char *fuse_linker_plugin = "fuse-linker-plugin"; /* We'll use ld if we can't find collect2. */ if (! strcmp (linker_name_spec, "collect2")) @@ -7483,6 +7540,23 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n" if (s == NULL) linker_name_spec = "ld"; } + + if (switch_matches (fuse_linker_plugin, + fuse_linker_plugin + strlen (fuse_linker_plugin), 0)) + { + linker_plugin_file_spec = find_a_file (&exec_prefixes, + "liblto_plugin.so", X_OK, + false); + if (!linker_plugin_file_spec) + fatal ("-fuse-linker-plugin, but liblto_plugin.so not found"); + + lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a", + R_OK, true); + if (!lto_libgcc_spec) + fatal ("could not find libgcc.a"); + } + lto_gcc_spec = argv[0]; + /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect. */ putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH", false); diff --git a/gcc/gcse.c b/gcc/gcse.c index 803ab3e5a14..7ccb05e1d85 100644 --- a/gcc/gcse.c +++ b/gcc/gcse.c @@ -2276,8 +2276,7 @@ try_replace_reg (rtx from, rtx to, rtx insn) with our replacement. */ if (note != 0 && REG_NOTE_KIND (note) == REG_EQUAL) set_unique_reg_note (insn, REG_EQUAL, - simplify_replace_rtx (XEXP (note, 0), from, - copy_rtx (to))); + simplify_replace_rtx (XEXP (note, 0), from, to)); if (!success && set && reg_mentioned_p (from, SET_SRC (set))) { /* If above failed and this is a single set, try to simplify the source of @@ -3038,12 +3037,12 @@ bypass_block (basic_block bb, rtx setcc, rtx jump) src = SET_SRC (pc_set (jump)); if (setcc != NULL) - src = simplify_replace_rtx (src, - SET_DEST (PATTERN (setcc)), - SET_SRC (PATTERN (setcc))); + src = simplify_replace_rtx (src, + SET_DEST (PATTERN (setcc)), + SET_SRC (PATTERN (setcc))); new_rtx = simplify_replace_rtx (src, reg_used->reg_rtx, - SET_SRC (set->expr)); + SET_SRC (set->expr)); /* Jump bypassing may have already placed instructions on edges of the CFG. We can't bypass an outgoing edge that diff --git a/gcc/gengtype.c b/gcc/gengtype.c index bb067368db4..32abf6eff12 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -141,8 +141,7 @@ static void oprintf (outf_p o, const char *S, ...) static outf_p output_files; /* The plugin input files and their number; in that case only - corresponding gt-.h are generated in the current - directory. */ + a single file is produced. */ static char** plugin_files; static size_t nb_plugin_files; /* the generated plugin output name & file */ @@ -1118,6 +1117,8 @@ adjust_field_rtx_def (type_p t, options_p ARG_UNUSED (opt)) t = scalar_tp, subname = "rt_int"; else if (i == VALUE && aindex == 0) t = scalar_tp, subname = "rt_int"; + else if (i == DEBUG_EXPR && aindex == 0) + t = tree_tp, subname = "rt_tree"; else if (i == REG && aindex == 1) t = scalar_tp, subname = "rt_int"; else if (i == REG && aindex == 2) @@ -1570,7 +1571,7 @@ open_base_files (void) "optabs.h", "libfuncs.h", "debug.h", "ggc.h", "cgraph.h", "tree-flow.h", "reload.h", "cpp-id-data.h", "tree-chrec.h", "cfglayout.h", "except.h", "output.h", "gimple.h", "cfgloop.h", - "target.h", NULL + "target.h", "ipa-prop.h", NULL }; const char *const *ifp; outf_p gtype_desc_c; @@ -2719,6 +2720,9 @@ write_types (outf_p output_header, type_p structures, type_p param_structs, type_p s; oprintf (output_header, "\n/* %s*/\n", wtd->comment); + /* We first emit the macros and the declarations. Functions' code is + emitted afterwards. This is needed in plugin mode. */ + oprintf (output_header, "/* macros and declarations */\n"); for (s = structures; s; s = s->next) if (s->gc_used == GC_POINTED_TO || s->gc_used == GC_MAYBE_POINTED_TO) @@ -2767,21 +2771,11 @@ write_types (outf_p output_header, type_p structures, type_p param_structs, s->u.s.tag); continue; } - - if (s->kind == TYPE_LANG_STRUCT) - { - type_p ss; - for (ss = s->u.s.lang_struct; ss; ss = ss->next) - write_func_for_structure (s, ss, NULL, wtd); - } - else - write_func_for_structure (s, s, NULL, wtd); } for (s = param_structs; s; s = s->next) if (s->gc_used == GC_POINTED_TO) { - type_p * param = s->u.param_struct.param; type_p stru = s->u.param_struct.stru; /* Declare the marker procedure. */ @@ -2795,7 +2789,41 @@ write_types (outf_p output_header, type_p structures, type_p param_structs, s->u.s.tag); continue; } + } + + /* At last we emit the functions code. */ + oprintf (output_header, "\n/* functions code */\n"); + for (s = structures; s; s = s->next) + if (s->gc_used == GC_POINTED_TO + || s->gc_used == GC_MAYBE_POINTED_TO) + { + options_p opt; + if (s->gc_used == GC_MAYBE_POINTED_TO + && s->u.s.line.file == NULL) + continue; + for (opt = s->u.s.opt; opt; opt = opt->next) + if (strcmp (opt->name, "ptr_alias") == 0) + break; + if (opt) + continue; + + if (s->kind == TYPE_LANG_STRUCT) + { + type_p ss; + for (ss = s->u.s.lang_struct; ss; ss = ss->next) + write_func_for_structure (s, ss, NULL, wtd); + } + else + write_func_for_structure (s, s, NULL, wtd); + } + for (s = param_structs; s; s = s->next) + if (s->gc_used == GC_POINTED_TO) + { + type_p *param = s->u.param_struct.param; + type_p stru = s->u.param_struct.stru; + if (stru->u.s.line.file == NULL) + continue; if (stru->kind == TYPE_LANG_STRUCT) { type_p ss; diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c index 744355e3de3..adb32880cfa 100644 --- a/gcc/ggc-page.c +++ b/gcc/ggc-page.c @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "params.h" #include "tree-flow.h" +#include "cfgloop.h" #include "plugin.h" /* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a @@ -157,6 +158,24 @@ along with GCC; see the file COPYING3. If not see #define OFFSET_TO_BIT(OFFSET, ORDER) \ (((OFFSET) * DIV_MULT (ORDER)) >> DIV_SHIFT (ORDER)) +/* We use this structure to determine the alignment required for + allocations. For power-of-two sized allocations, that's not a + problem, but it does matter for odd-sized allocations. + We do not care about alignment for floating-point types. */ + +struct max_alignment { + char c; + union { + HOST_WIDEST_INT i; + void *p; + } u; +}; + +/* The biggest alignment required. */ + +#define MAX_ALIGNMENT (offsetof (struct max_alignment, u)) + + /* The number of extra orders, not corresponding to power-of-two sized objects. */ @@ -173,42 +192,35 @@ along with GCC; see the file COPYING3. If not see thing you need to do to add a new special allocation size. */ static const size_t extra_order_size_table[] = { - sizeof (struct var_ann_d), + /* Extra orders for small non-power-of-two multiples of MAX_ALIGNMENT. + There are a lot of structures with these sizes and explicitly + listing them risks orders being dropped because they changed size. */ + MAX_ALIGNMENT * 3, + MAX_ALIGNMENT * 5, + MAX_ALIGNMENT * 6, + MAX_ALIGNMENT * 7, + MAX_ALIGNMENT * 9, + MAX_ALIGNMENT * 10, + MAX_ALIGNMENT * 11, + MAX_ALIGNMENT * 12, + MAX_ALIGNMENT * 13, + MAX_ALIGNMENT * 14, + MAX_ALIGNMENT * 15, sizeof (struct tree_decl_non_common), sizeof (struct tree_field_decl), sizeof (struct tree_parm_decl), sizeof (struct tree_var_decl), - sizeof (struct tree_list), - sizeof (struct tree_ssa_name), + sizeof (struct tree_type), sizeof (struct function), sizeof (struct basic_block_def), - sizeof (bitmap_element), - sizeof (bitmap_head), - TREE_EXP_SIZE (2), - RTL_SIZE (2), /* MEM, PLUS, etc. */ - RTL_SIZE (9), /* INSN */ + sizeof (struct cgraph_node), + sizeof (struct loop), }; /* The total number of orders. */ #define NUM_ORDERS (HOST_BITS_PER_PTR + NUM_EXTRA_ORDERS) -/* We use this structure to determine the alignment required for - allocations. For power-of-two sized allocations, that's not a - problem, but it does matter for odd-sized allocations. */ - -struct max_alignment { - char c; - union { - HOST_WIDEST_INT i; - long double d; - } u; -}; - -/* The biggest alignment required. */ - -#define MAX_ALIGNMENT (offsetof (struct max_alignment, u)) - /* Compute the smallest nonnegative number which when added to X gives a multiple of F. */ diff --git a/gcc/gimple-iterator.c b/gcc/gimple-iterator.c index 66927d67c2c..c3ca0e37501 100644 --- a/gcc/gimple-iterator.c +++ b/gcc/gimple-iterator.c @@ -358,7 +358,8 @@ gsi_split_seq_before (gimple_stmt_iterator *i) /* Replace the statement pointed-to by GSI to STMT. If UPDATE_EH_INFO is true, the exception handling information of the original - statement is moved to the new statement. */ + statement is moved to the new statement. Assignments must only be + replaced with assignments to the same LHS. */ void gsi_replace (gimple_stmt_iterator *gsi, gimple stmt, bool update_eh_info) @@ -368,6 +369,9 @@ gsi_replace (gimple_stmt_iterator *gsi, gimple stmt, bool update_eh_info) if (stmt == orig_stmt) return; + gcc_assert (!gimple_has_lhs (orig_stmt) + || gimple_get_lhs (orig_stmt) == gimple_get_lhs (stmt)); + gimple_set_location (stmt, gimple_location (orig_stmt)); gimple_set_bb (stmt, gsi_bb (*gsi)); @@ -470,6 +474,8 @@ gsi_remove (gimple_stmt_iterator *i, bool remove_permanently) gimple_seq_node cur, next, prev; gimple stmt = gsi_stmt (*i); + insert_debug_temps_for_defs (i); + /* Free all the data flow information for STMT. */ gimple_set_bb (stmt, NULL); delink_stmt_imm_use (stmt); diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index b58fd7b42f5..cce31e946ff 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -76,6 +76,9 @@ struct lower_data of the function. */ VEC(return_statements_t,heap) *return_statements; + /* True if the current statement cannot fall through. */ + bool cannot_fallthru; + /* True if the function calls __builtin_setjmp. */ bool calls_builtin_setjmp; }; @@ -317,7 +320,12 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data) } -/* Lower statement GSI. DATA is passed through the recursion. */ +/* Lower statement GSI. DATA is passed through the recursion. We try to + track the fallthruness of statements and get rid of unreachable return + statements in order to prevent the EH lowering pass from adding useless + edges that can cause bogus warnings to be issued later; this guess need + not be 100% accurate, simply be conservative and reset cannot_fallthru + to false if we don't know. */ static void lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) @@ -330,36 +338,61 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) { case GIMPLE_BIND: lower_gimple_bind (gsi, data); + /* Propagate fallthruness. */ return; case GIMPLE_COND: - /* The gimplifier has already lowered this into gotos. */ - break; + case GIMPLE_GOTO: + case GIMPLE_SWITCH: + data->cannot_fallthru = true; + gsi_next (gsi); + return; case GIMPLE_RETURN: - lower_gimple_return (gsi, data); + if (data->cannot_fallthru) + { + gsi_remove (gsi, false); + /* Propagate fallthruness. */ + } + else + { + lower_gimple_return (gsi, data); + data->cannot_fallthru = true; + } return; case GIMPLE_TRY: - lower_sequence (gimple_try_eval (stmt), data); - lower_sequence (gimple_try_cleanup (stmt), data); + { + bool try_cannot_fallthru; + lower_sequence (gimple_try_eval (stmt), data); + try_cannot_fallthru = data->cannot_fallthru; + data->cannot_fallthru = false; + lower_sequence (gimple_try_cleanup (stmt), data); + /* See gimple_stmt_may_fallthru for the rationale. */ + if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY) + { + data->cannot_fallthru |= try_cannot_fallthru; + gsi_next (gsi); + return; + } + } break; case GIMPLE_CATCH: + data->cannot_fallthru = false; lower_sequence (gimple_catch_handler (stmt), data); break; case GIMPLE_EH_FILTER: + data->cannot_fallthru = false; lower_sequence (gimple_eh_filter_failure (stmt), data); break; case GIMPLE_NOP: case GIMPLE_ASM: case GIMPLE_ASSIGN: - case GIMPLE_GOTO: case GIMPLE_PREDICT: case GIMPLE_LABEL: - case GIMPLE_SWITCH: case GIMPLE_EH_MUST_NOT_THROW: case GIMPLE_OMP_FOR: case GIMPLE_OMP_SECTIONS: @@ -383,8 +416,16 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP) { - data->calls_builtin_setjmp = true; lower_builtin_setjmp (gsi); + data->cannot_fallthru = false; + data->calls_builtin_setjmp = true; + return; + } + + if (decl && (flags_from_decl_or_type (decl) & ECF_NORETURN)) + { + data->cannot_fallthru = true; + gsi_next (gsi); return; } } @@ -392,13 +433,16 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + data->cannot_fallthru = false; lower_omp_directive (gsi, data); + data->cannot_fallthru = false; return; default: gcc_unreachable (); } + data->cannot_fallthru = false; gsi_next (gsi); } @@ -647,9 +691,9 @@ gimple_stmt_may_fallthru (gimple stmt) return false; case GIMPLE_SWITCH: - /* Switch has already been lowered and represents a - branch to a selected label and hence can not fall through. */ - return true; + /* Switch has already been lowered and represents a branch + to a selected label and hence can't fall through. */ + return false; case GIMPLE_COND: /* GIMPLE_COND's are already lowered into a two-way branch. They @@ -675,13 +719,10 @@ gimple_stmt_may_fallthru (gimple stmt) return (gimple_seq_may_fallthru (gimple_try_eval (stmt)) && gimple_seq_may_fallthru (gimple_try_cleanup (stmt))); - case GIMPLE_ASSIGN: - return true; - case GIMPLE_CALL: /* Functions that do not return do not fall through. */ return (gimple_call_flags (stmt) & ECF_NORETURN) == 0; - + default: return true; } @@ -731,7 +772,7 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) gsi_remove (gsi, false); } -/* Lower a __builtin_setjmp TSI. +/* Lower a __builtin_setjmp GSI. __builtin_setjmp is passed a pointer to an array of five words (not all will be used on all machines). It operates similarly to the C diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 3d3134beaa6..4f6c4470c9d 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -254,6 +254,7 @@ dump_unary_rhs (pretty_printer *buffer, gimple gs, int spc, int flags) break; case FIXED_CONVERT_EXPR: + case ADDR_SPACE_CONVERT_EXPR: case FIX_TRUNC_EXPR: case FLOAT_EXPR: CASE_CONVERT: diff --git a/gcc/gimple.c b/gcc/gimple.c index 425463c31ca..676e3fd4678 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" +#include "target.h" #include "tree.h" #include "ggc.h" #include "hard-reg-set.h" @@ -33,8 +34,19 @@ along with GCC; see the file COPYING3. If not see #include "tree-flow.h" #include "value-prof.h" #include "flags.h" +#include "alias.h" #include "demangle.h" +/* Global type table. FIXME lto, it should be possible to re-use some + of the type hashing routines in tree.c (type_hash_canon, type_hash_lookup, + etc), but those assume that types were built with the various + build_*_type routines which is not the case with the streamer. */ +static htab_t gimple_types; +static struct pointer_map_t *type_hash_cache; + +/* Global type comparison cache. */ +static htab_t gtc_visited; +static struct obstack gtc_ob; /* All the tuples have their operand vector (if present) at the very bottom of the structure. Therefore, the offset required to find the @@ -115,8 +127,7 @@ gimple_size (enum gimple_code code) /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS operands. */ -#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO) -static gimple +gimple gimple_alloc_stat (enum gimple_code code, unsigned num_ops MEM_STAT_DECL) { size_t size; @@ -613,7 +624,7 @@ gimple_build_eh_must_not_throw (tree decl) gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); gcc_assert (flags_from_decl_or_type (decl) & ECF_NORETURN); - p->gimple_eh_mnt.fndecl = decl; + gimple_eh_must_not_throw_set_fndecl (p, decl); return p; } @@ -3000,6 +3011,1226 @@ gimple_call_copy_skip_args (gimple stmt, bitmap args_to_skip) } +static hashval_t gimple_type_hash (const void *); + +/* Structure used to maintain a cache of some type pairs compared by + gimple_types_compatible_p when comparing aggregate types. There are + four possible values for SAME_P: + + -2: The pair (T1, T2) has just been inserted in the table. + -1: The pair (T1, T2) is currently being compared. + 0: T1 and T2 are different types. + 1: T1 and T2 are the same type. + + This table is only used when comparing aggregate types to avoid + infinite recursion due to self-referential types. */ +struct type_pair_d +{ + unsigned int uid1; + unsigned int uid2; + int same_p; +}; +typedef struct type_pair_d *type_pair_t; + +/* Return a hash value for the type pair pointed-to by P. */ + +static hashval_t +type_pair_hash (const void *p) +{ + const struct type_pair_d *pair = (const struct type_pair_d *) p; + hashval_t val1 = pair->uid1; + hashval_t val2 = pair->uid2; + return (iterative_hash_hashval_t (val2, val1) + ^ iterative_hash_hashval_t (val1, val2)); +} + +/* Compare two type pairs pointed-to by P1 and P2. */ + +static int +type_pair_eq (const void *p1, const void *p2) +{ + const struct type_pair_d *pair1 = (const struct type_pair_d *) p1; + const struct type_pair_d *pair2 = (const struct type_pair_d *) p2; + return ((pair1->uid1 == pair2->uid1 && pair1->uid2 == pair2->uid2) + || (pair1->uid1 == pair2->uid2 && pair1->uid2 == pair2->uid1)); +} + +/* Lookup the pair of types T1 and T2 in *VISITED_P. Insert a new + entry if none existed. */ + +static type_pair_t +lookup_type_pair (tree t1, tree t2, htab_t *visited_p, struct obstack *ob_p) +{ + struct type_pair_d pair; + type_pair_t p; + void **slot; + + if (*visited_p == NULL) + { + *visited_p = htab_create (251, type_pair_hash, type_pair_eq, NULL); + gcc_obstack_init (ob_p); + } + + pair.uid1 = TYPE_UID (t1); + pair.uid2 = TYPE_UID (t2); + slot = htab_find_slot (*visited_p, &pair, INSERT); + + if (*slot) + p = *((type_pair_t *) slot); + else + { + p = XOBNEW (ob_p, struct type_pair_d); + p->uid1 = TYPE_UID (t1); + p->uid2 = TYPE_UID (t2); + p->same_p = -2; + *slot = (void *) p; + } + + return p; +} + + +/* Return true if T1 and T2 have the same name. If FOR_COMPLETION_P is + true then if any type has no name return false, otherwise return + true if both types have no names. */ + +static bool +compare_type_names_p (tree t1, tree t2, bool for_completion_p) +{ + tree name1 = TYPE_NAME (t1); + tree name2 = TYPE_NAME (t2); + + /* Consider anonymous types all unique for completion. */ + if (for_completion_p + && (!name1 || !name2)) + return false; + + if (name1 && TREE_CODE (name1) == TYPE_DECL) + { + name1 = DECL_NAME (name1); + if (for_completion_p + && !name1) + return false; + } + gcc_assert (!name1 || TREE_CODE (name1) == IDENTIFIER_NODE); + + if (name2 && TREE_CODE (name2) == TYPE_DECL) + { + name2 = DECL_NAME (name2); + if (for_completion_p + && !name2) + return false; + } + gcc_assert (!name2 || TREE_CODE (name2) == IDENTIFIER_NODE); + + /* Identifiers can be compared with pointer equality rather + than a string comparison. */ + if (name1 == name2) + return true; + + return false; +} + +/* Return true if the field decls F1 and F2 are at the same offset. */ + +static bool +compare_field_offset (tree f1, tree f2) +{ + if (DECL_OFFSET_ALIGN (f1) == DECL_OFFSET_ALIGN (f2)) + return (operand_equal_p (DECL_FIELD_OFFSET (f1), + DECL_FIELD_OFFSET (f2), 0) + && tree_int_cst_equal (DECL_FIELD_BIT_OFFSET (f1), + DECL_FIELD_BIT_OFFSET (f2))); + + /* Fortran and C do not always agree on what DECL_OFFSET_ALIGN + should be, so handle differing ones specially by decomposing + the offset into a byte and bit offset manually. */ + if (host_integerp (DECL_FIELD_OFFSET (f1), 0) + && host_integerp (DECL_FIELD_OFFSET (f2), 0)) + { + unsigned HOST_WIDE_INT byte_offset1, byte_offset2; + unsigned HOST_WIDE_INT bit_offset1, bit_offset2; + bit_offset1 = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (f1)); + byte_offset1 = (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (f1)) + + bit_offset1 / BITS_PER_UNIT); + bit_offset2 = TREE_INT_CST_LOW (DECL_FIELD_BIT_OFFSET (f2)); + byte_offset2 = (TREE_INT_CST_LOW (DECL_FIELD_OFFSET (f2)) + + bit_offset2 / BITS_PER_UNIT); + if (byte_offset1 != byte_offset2) + return false; + return bit_offset1 % BITS_PER_UNIT == bit_offset2 % BITS_PER_UNIT; + } + + return false; +} + +/* Return 1 iff T1 and T2 are structurally identical. + Otherwise, return 0. */ + +static int +gimple_types_compatible_p (tree t1, tree t2) +{ + type_pair_t p = NULL; + + /* Check first for the obvious case of pointer identity. */ + if (t1 == t2) + return 1; + + /* Check that we have two types to compare. */ + if (t1 == NULL_TREE || t2 == NULL_TREE) + return 0; + + /* Can't be the same type if the types don't have the same code. */ + if (TREE_CODE (t1) != TREE_CODE (t2)) + return 0; + + /* Can't be the same type if they have different CV qualifiers. */ + if (TYPE_QUALS (t1) != TYPE_QUALS (t2)) + return 0; + + /* Void types are always the same. */ + if (TREE_CODE (t1) == VOID_TYPE) + return 1; + + /* For numerical types do some simple checks before doing three + hashtable queries. */ + if (INTEGRAL_TYPE_P (t1) + || SCALAR_FLOAT_TYPE_P (t1) + || FIXED_POINT_TYPE_P (t1) + || TREE_CODE (t1) == VECTOR_TYPE + || TREE_CODE (t1) == COMPLEX_TYPE + || TREE_CODE (t1) == OFFSET_TYPE) + { + /* Can't be the same type if they have different alignment, + sign, precision or mode. */ + if (TYPE_ALIGN (t1) != TYPE_ALIGN (t2) + || TYPE_PRECISION (t1) != TYPE_PRECISION (t2) + || TYPE_MODE (t1) != TYPE_MODE (t2) + || TYPE_UNSIGNED (t1) != TYPE_UNSIGNED (t2)) + return 0; + + if (TREE_CODE (t1) == INTEGER_TYPE + && (TYPE_IS_SIZETYPE (t1) != TYPE_IS_SIZETYPE (t2) + || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2))) + return 0; + + /* That's all we need to check for float and fixed-point types. */ + if (SCALAR_FLOAT_TYPE_P (t1) + || FIXED_POINT_TYPE_P (t1)) + return 1; + + /* Perform cheap tail-recursion for vector and complex types. */ + if (TREE_CODE (t1) == VECTOR_TYPE + || TREE_CODE (t1) == COMPLEX_TYPE) + return gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)); + + /* For integral types fall thru to more complex checks. */ + } + + /* If the hash values of t1 and t2 are different the types can't + possibly be the same. This helps keeping the type-pair hashtable + small, only tracking comparisons for hash collisions. */ + if (gimple_type_hash (t1) != gimple_type_hash (t2)) + return 0; + + /* If we've visited this type pair before (in the case of aggregates + with self-referential types), and we made a decision, return it. */ + p = lookup_type_pair (t1, t2, >c_visited, >c_ob); + if (p->same_p == 0 || p->same_p == 1) + { + /* We have already decided whether T1 and T2 are the + same, return the cached result. */ + return p->same_p == 1; + } + else if (p->same_p == -1) + { + /* We are currently comparing this pair of types, assume + that they are the same and let the caller decide. */ + return 1; + } + + gcc_assert (p->same_p == -2); + + /* Mark the (T1, T2) comparison in progress. */ + p->same_p = -1; + + /* If their attributes are not the same they can't be the same type. */ + if (!attribute_list_equal (TYPE_ATTRIBUTES (t1), TYPE_ATTRIBUTES (t2))) + goto different_types; + + /* Do type-specific comparisons. */ + switch (TREE_CODE (t1)) + { + case ARRAY_TYPE: + /* Array types are the same if the element types are the same and + the number of elements are the same. */ + if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)) + || TYPE_STRING_FLAG (t1) != TYPE_STRING_FLAG (t2) + || TYPE_NONALIASED_COMPONENT (t1) != TYPE_NONALIASED_COMPONENT (t2)) + goto different_types; + else + { + tree i1 = TYPE_DOMAIN (t1); + tree i2 = TYPE_DOMAIN (t2); + + /* For an incomplete external array, the type domain can be + NULL_TREE. Check this condition also. */ + if (i1 == NULL_TREE && i2 == NULL_TREE) + goto same_types; + else if (i1 == NULL_TREE || i2 == NULL_TREE) + goto different_types; + /* If for a complete array type the possibly gimplified sizes + are different the types are different. */ + else if (((TYPE_SIZE (i1) != NULL) ^ (TYPE_SIZE (i2) != NULL)) + || (TYPE_SIZE (i1) + && TYPE_SIZE (i2) + && !operand_equal_p (TYPE_SIZE (i1), TYPE_SIZE (i2), 0))) + goto different_types; + else + { + tree min1 = TYPE_MIN_VALUE (i1); + tree min2 = TYPE_MIN_VALUE (i2); + tree max1 = TYPE_MAX_VALUE (i1); + tree max2 = TYPE_MAX_VALUE (i2); + + /* The minimum/maximum values have to be the same. */ + if ((min1 == min2 + || (min1 && min2 && operand_equal_p (min1, min2, 0))) + && (max1 == max2 + || (max1 && max2 && operand_equal_p (max1, max2, 0)))) + goto same_types; + else + goto different_types; + } + } + + case METHOD_TYPE: + /* Method types should belong to the same class. */ + if (!gimple_types_compatible_p (TYPE_METHOD_BASETYPE (t1), + TYPE_METHOD_BASETYPE (t2))) + goto different_types; + + /* Fallthru */ + + case FUNCTION_TYPE: + /* Function types are the same if the return type and arguments types + are the same. */ + if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) + goto different_types; + else + { + if (!targetm.comp_type_attributes (t1, t2)) + goto different_types; + + if (TYPE_ARG_TYPES (t1) == TYPE_ARG_TYPES (t2)) + goto same_types; + else + { + tree parms1, parms2; + + for (parms1 = TYPE_ARG_TYPES (t1), parms2 = TYPE_ARG_TYPES (t2); + parms1 && parms2; + parms1 = TREE_CHAIN (parms1), parms2 = TREE_CHAIN (parms2)) + { + if (!gimple_types_compatible_p (TREE_VALUE (parms1), + TREE_VALUE (parms2))) + goto different_types; + } + + if (parms1 || parms2) + goto different_types; + + goto same_types; + } + } + + case OFFSET_TYPE: + { + if (!gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2)) + || !gimple_types_compatible_p (TYPE_OFFSET_BASETYPE (t1), + TYPE_OFFSET_BASETYPE (t2))) + goto different_types; + + goto same_types; + } + + case POINTER_TYPE: + case REFERENCE_TYPE: + { + /* If the two pointers have different ref-all attributes, + they can't be the same type. */ + if (TYPE_REF_CAN_ALIAS_ALL (t1) != TYPE_REF_CAN_ALIAS_ALL (t2)) + goto different_types; + + /* If one pointer points to an incomplete type variant of + the other pointed-to type they are the same. */ + if (TREE_CODE (TREE_TYPE (t1)) == TREE_CODE (TREE_TYPE (t2)) + && RECORD_OR_UNION_TYPE_P (TREE_TYPE (t1)) + && (!COMPLETE_TYPE_P (TREE_TYPE (t1)) + || !COMPLETE_TYPE_P (TREE_TYPE (t2))) + && compare_type_names_p (TYPE_MAIN_VARIANT (TREE_TYPE (t1)), + TYPE_MAIN_VARIANT (TREE_TYPE (t2)), true)) + { + /* Replace the pointed-to incomplete type with the + complete one. */ + if (COMPLETE_TYPE_P (TREE_TYPE (t2))) + TREE_TYPE (t1) = TREE_TYPE (t2); + else + TREE_TYPE (t2) = TREE_TYPE (t1); + goto same_types; + } + + /* Otherwise, pointer and reference types are the same if the + pointed-to types are the same. */ + if (gimple_types_compatible_p (TREE_TYPE (t1), TREE_TYPE (t2))) + goto same_types; + + goto different_types; + } + + case INTEGER_TYPE: + case BOOLEAN_TYPE: + { + tree min1 = TYPE_MIN_VALUE (t1); + tree max1 = TYPE_MAX_VALUE (t1); + tree min2 = TYPE_MIN_VALUE (t2); + tree max2 = TYPE_MAX_VALUE (t2); + bool min_equal_p = false; + bool max_equal_p = false; + + /* If either type has a minimum value, the other type must + have the same. */ + if (min1 == NULL_TREE && min2 == NULL_TREE) + min_equal_p = true; + else if (min1 && min2 && operand_equal_p (min1, min2, 0)) + min_equal_p = true; + + /* Likewise, if either type has a maximum value, the other + type must have the same. */ + if (max1 == NULL_TREE && max2 == NULL_TREE) + max_equal_p = true; + else if (max1 && max2 && operand_equal_p (max1, max2, 0)) + max_equal_p = true; + + if (!min_equal_p || !max_equal_p) + goto different_types; + + goto same_types; + } + + case ENUMERAL_TYPE: + { + /* FIXME lto, we cannot check bounds on enumeral types because + different front ends will produce different values. + In C, enumeral types are integers, while in C++ each element + will have its own symbolic value. We should decide how enums + are to be represented in GIMPLE and have each front end lower + to that. */ + tree v1, v2; + + /* For enumeral types, all the values must be the same. */ + if (TYPE_VALUES (t1) == TYPE_VALUES (t2)) + goto same_types; + + for (v1 = TYPE_VALUES (t1), v2 = TYPE_VALUES (t2); + v1 && v2; + v1 = TREE_CHAIN (v1), v2 = TREE_CHAIN (v2)) + { + tree c1 = TREE_VALUE (v1); + tree c2 = TREE_VALUE (v2); + + if (TREE_CODE (c1) == CONST_DECL) + c1 = DECL_INITIAL (c1); + + if (TREE_CODE (c2) == CONST_DECL) + c2 = DECL_INITIAL (c2); + + if (tree_int_cst_equal (c1, c2) != 1) + goto different_types; + } + + /* If one enumeration has more values than the other, they + are not the same. */ + if (v1 || v2) + goto different_types; + + goto same_types; + } + + case RECORD_TYPE: + case UNION_TYPE: + case QUAL_UNION_TYPE: + { + tree f1, f2; + + /* If one type requires structural equality checks and the + other doesn't, do not merge the types. */ + if (TYPE_STRUCTURAL_EQUALITY_P (t1) + != TYPE_STRUCTURAL_EQUALITY_P (t2)) + goto different_types; + + /* The struct tags shall compare equal. */ + if (!compare_type_names_p (TYPE_MAIN_VARIANT (t1), + TYPE_MAIN_VARIANT (t2), false)) + goto different_types; + + /* For aggregate types, all the fields must be the same. */ + for (f1 = TYPE_FIELDS (t1), f2 = TYPE_FIELDS (t2); + f1 && f2; + f1 = TREE_CHAIN (f1), f2 = TREE_CHAIN (f2)) + { + /* The fields must have the same name, offset and type. */ + if (DECL_NAME (f1) != DECL_NAME (f2) + || DECL_NONADDRESSABLE_P (f1) != DECL_NONADDRESSABLE_P (f2) + || !compare_field_offset (f1, f2) + || !gimple_types_compatible_p (TREE_TYPE (f1), + TREE_TYPE (f2))) + goto different_types; + } + + /* If one aggregate has more fields than the other, they + are not the same. */ + if (f1 || f2) + goto different_types; + + goto same_types; + } + + default: + gcc_unreachable (); + } + + /* Common exit path for types that are not compatible. */ +different_types: + p->same_p = 0; + return 0; + + /* Common exit path for types that are compatible. */ +same_types: + p->same_p = 1; + return 1; +} + + + + +/* Per pointer state for the SCC finding. The on_sccstack flag + is not strictly required, it is true when there is no hash value + recorded for the type and false otherwise. But querying that + is slower. */ + +struct sccs +{ + unsigned int dfsnum; + unsigned int low; + bool on_sccstack; + hashval_t hash; +}; + +static unsigned int next_dfs_num; + +static hashval_t +iterative_hash_gimple_type (tree, hashval_t, VEC(tree, heap) **, + struct pointer_map_t *, struct obstack *); + +/* DFS visit the edge from the callers type with state *STATE to T. + Update the callers type hash V with the hash for T if it is not part + of the SCC containing the callers type and return it. + SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. */ + +static hashval_t +visit (tree t, struct sccs *state, hashval_t v, + VEC (tree, heap) **sccstack, + struct pointer_map_t *sccstate, + struct obstack *sccstate_obstack) +{ + struct sccs *cstate = NULL; + void **slot; + + /* If there is a hash value recorded for this type then it can't + possibly be part of our parent SCC. Simply mix in its hash. */ + if ((slot = pointer_map_contains (type_hash_cache, t))) + return iterative_hash_hashval_t ((hashval_t) (size_t) *slot, v); + + if ((slot = pointer_map_contains (sccstate, t)) != NULL) + cstate = (struct sccs *)*slot; + if (!cstate) + { + hashval_t tem; + /* Not yet visited. DFS recurse. */ + tem = iterative_hash_gimple_type (t, v, + sccstack, sccstate, sccstate_obstack); + if (!cstate) + cstate = (struct sccs *)* pointer_map_contains (sccstate, t); + state->low = MIN (state->low, cstate->low); + /* If the type is no longer on the SCC stack and thus is not part + of the parents SCC mix in its hash value. Otherwise we will + ignore the type for hashing purposes and return the unaltered + hash value. */ + if (!cstate->on_sccstack) + return tem; + } + if (cstate->dfsnum < state->dfsnum + && cstate->on_sccstack) + state->low = MIN (cstate->dfsnum, state->low); + + /* We are part of our parents SCC, skip this type during hashing + and return the unaltered hash value. */ + return v; +} + +/* Hash NAME with the previous hash value V and return it. */ + +static hashval_t +iterative_hash_name (tree name, hashval_t v) +{ + if (!name) + return v; + if (TREE_CODE (name) == TYPE_DECL) + name = DECL_NAME (name); + if (!name) + return v; + gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE); + return iterative_hash_object (IDENTIFIER_HASH_VALUE (name), v); +} + +/* Returning a hash value for gimple type TYPE combined with VAL. + SCCSTACK, SCCSTATE and SCCSTATE_OBSTACK are state for the DFS walk done. + + To hash a type we end up hashing in types that are reachable. + Through pointers we can end up with cycles which messes up the + required property that we need to compute the same hash value + for structurally equivalent types. To avoid this we have to + hash all types in a cycle (the SCC) in a commutative way. The + easiest way is to not mix in the hashes of the SCC members at + all. To make this work we have to delay setting the hash + values of the SCC until it is complete. */ + +static hashval_t +iterative_hash_gimple_type (tree type, hashval_t val, + VEC(tree, heap) **sccstack, + struct pointer_map_t *sccstate, + struct obstack *sccstate_obstack) +{ + hashval_t v; + void **slot; + struct sccs *state; + +#ifdef ENABLE_CHECKING + /* Not visited during this DFS walk nor during previous walks. */ + gcc_assert (!pointer_map_contains (type_hash_cache, type) + && !pointer_map_contains (sccstate, type)); +#endif + state = XOBNEW (sccstate_obstack, struct sccs); + *pointer_map_insert (sccstate, type) = state; + + VEC_safe_push (tree, heap, *sccstack, type); + state->dfsnum = next_dfs_num++; + state->low = state->dfsnum; + state->on_sccstack = true; + + /* Combine a few common features of types so that types are grouped into + smaller sets; when searching for existing matching types to merge, + only existing types having the same features as the new type will be + checked. */ + v = iterative_hash_hashval_t (TREE_CODE (type), 0); + v = iterative_hash_hashval_t (TYPE_QUALS (type), v); + v = iterative_hash_hashval_t (TREE_ADDRESSABLE (type), v); + + /* Do not hash the types size as this will cause differences in + hash values for the complete vs. the incomplete type variant. */ + + /* Incorporate common features of numerical types. */ + if (INTEGRAL_TYPE_P (type) + || SCALAR_FLOAT_TYPE_P (type) + || FIXED_POINT_TYPE_P (type)) + { + v = iterative_hash_hashval_t (TYPE_PRECISION (type), v); + v = iterative_hash_hashval_t (TYPE_MODE (type), v); + v = iterative_hash_hashval_t (TYPE_UNSIGNED (type), v); + } + + /* For pointer and reference types, fold in information about the type + pointed to but do not recurse into possibly incomplete types to + avoid hash differences for complete vs. incomplete types. */ + if (POINTER_TYPE_P (type)) + { + if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (type))) + { + v = iterative_hash_hashval_t (TREE_CODE (TREE_TYPE (type)), v); + v = iterative_hash_name + (TYPE_NAME (TYPE_MAIN_VARIANT (TREE_TYPE (type))), v); + } + else + v = visit (TREE_TYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + } + + /* For integer types hash the types min/max values and the string flag. */ + if (TREE_CODE (type) == INTEGER_TYPE) + { + v = iterative_hash_expr (TYPE_MIN_VALUE (type), v); + v = iterative_hash_expr (TYPE_MAX_VALUE (type), v); + v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); + } + + /* For array types hash their domain and the string flag. */ + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_DOMAIN (type)) + { + v = iterative_hash_hashval_t (TYPE_STRING_FLAG (type), v); + v = visit (TYPE_DOMAIN (type), state, v, + sccstack, sccstate, sccstate_obstack); + } + + /* Recurse for aggregates with a single element type. */ + if (TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == COMPLEX_TYPE + || TREE_CODE (type) == VECTOR_TYPE) + v = visit (TREE_TYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + + /* Incorporate function return and argument types. */ + if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE) + { + unsigned na; + tree p; + + /* For method types also incorporate their parent class. */ + if (TREE_CODE (type) == METHOD_TYPE) + v = visit (TYPE_METHOD_BASETYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + + v = visit (TREE_TYPE (type), state, v, + sccstack, sccstate, sccstate_obstack); + + for (p = TYPE_ARG_TYPES (type), na = 0; p; p = TREE_CHAIN (p)) + { + v = visit (TREE_VALUE (p), state, v, + sccstack, sccstate, sccstate_obstack); + na++; + } + + v = iterative_hash_hashval_t (na, v); + } + + if (TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE + || TREE_CODE (type) == QUAL_UNION_TYPE) + { + unsigned nf; + tree f; + + v = iterative_hash_name (TYPE_NAME (TYPE_MAIN_VARIANT (type)), v); + + for (f = TYPE_FIELDS (type), nf = 0; f; f = TREE_CHAIN (f)) + { + v = iterative_hash_name (DECL_NAME (f), v); + v = visit (TREE_TYPE (f), state, v, + sccstack, sccstate, sccstate_obstack); + nf++; + } + + v = iterative_hash_hashval_t (nf, v); + } + + /* Record hash for us. */ + state->hash = v; + + /* See if we found an SCC. */ + if (state->low == state->dfsnum) + { + tree x; + + /* Pop off the SCC and set its hash values. */ + do + { + struct sccs *cstate; + x = VEC_pop (tree, *sccstack); + gcc_assert (!pointer_map_contains (type_hash_cache, x)); + cstate = (struct sccs *)*pointer_map_contains (sccstate, x); + cstate->on_sccstack = false; + slot = pointer_map_insert (type_hash_cache, x); + *slot = (void *) (size_t) cstate->hash; + } + while (x != type); + } + + return iterative_hash_hashval_t (v, val); +} + + +/* Returns a hash value for P (assumed to be a type). The hash value + is computed using some distinguishing features of the type. Note + that we cannot use pointer hashing here as we may be dealing with + two distinct instances of the same type. + + This function should produce the same hash value for two compatible + types according to gimple_types_compatible_p. */ + +static hashval_t +gimple_type_hash (const void *p) +{ + const_tree t = (const_tree) p; + VEC(tree, heap) *sccstack = NULL; + struct pointer_map_t *sccstate; + struct obstack sccstate_obstack; + hashval_t val; + void **slot; + + if (type_hash_cache == NULL) + type_hash_cache = pointer_map_create (); + + if ((slot = pointer_map_contains (type_hash_cache, p)) != NULL) + return iterative_hash_hashval_t ((hashval_t) (size_t) *slot, 0); + + /* Perform a DFS walk and pre-hash all reachable types. */ + next_dfs_num = 1; + sccstate = pointer_map_create (); + gcc_obstack_init (&sccstate_obstack); + val = iterative_hash_gimple_type (CONST_CAST_TREE (t), 0, + &sccstack, sccstate, &sccstate_obstack); + VEC_free (tree, heap, sccstack); + pointer_map_destroy (sccstate); + obstack_free (&sccstate_obstack, NULL); + + return val; +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +gimple_type_eq (const void *p1, const void *p2) +{ + const_tree t1 = (const_tree) p1; + const_tree t2 = (const_tree) p2; + return gimple_types_compatible_p (CONST_CAST_TREE (t1), CONST_CAST_TREE (t2)); +} + + +/* Register type T in the global type table gimple_types. + If another type T', compatible with T, already existed in + gimple_types then return T', otherwise return T. This is used by + LTO to merge identical types read from different TUs. */ + +tree +gimple_register_type (tree t) +{ + void **slot; + + gcc_assert (TYPE_P (t)); + + /* Always register the main variant first. This is important so we + pick up the non-typedef variants as canonical, otherwise we'll end + up taking typedef ids for structure tags during comparison. */ + if (TYPE_MAIN_VARIANT (t) != t) + gimple_register_type (TYPE_MAIN_VARIANT (t)); + + if (gimple_types == NULL) + gimple_types = htab_create (16381, gimple_type_hash, gimple_type_eq, 0); + + slot = htab_find_slot (gimple_types, t, INSERT); + if (*slot + && *(tree *)slot != t) + { + tree new_type = (tree) *((tree *) slot); + + /* Do not merge types with different addressability. */ + gcc_assert (TREE_ADDRESSABLE (t) == TREE_ADDRESSABLE (new_type)); + + /* If t is not its main variant then make t unreachable from its + main variant list. Otherwise we'd queue up a lot of duplicates + there. */ + if (t != TYPE_MAIN_VARIANT (t)) + { + tree tem = TYPE_MAIN_VARIANT (t); + while (tem && TYPE_NEXT_VARIANT (tem) != t) + tem = TYPE_NEXT_VARIANT (tem); + if (tem) + TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t); + TYPE_NEXT_VARIANT (t) = NULL_TREE; + } + + /* If we are a pointer then remove us from the pointer-to or + reference-to chain. Otherwise we'd queue up a lot of duplicates + there. */ + if (TREE_CODE (t) == POINTER_TYPE) + { + if (TYPE_POINTER_TO (TREE_TYPE (t)) == t) + TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t); + else + { + tree tem = TYPE_POINTER_TO (TREE_TYPE (t)); + while (tem && TYPE_NEXT_PTR_TO (tem) != t) + tem = TYPE_NEXT_PTR_TO (tem); + if (tem) + TYPE_NEXT_PTR_TO (tem) = TYPE_NEXT_PTR_TO (t); + } + TYPE_NEXT_PTR_TO (t) = NULL_TREE; + } + else if (TREE_CODE (t) == REFERENCE_TYPE) + { + if (TYPE_REFERENCE_TO (TREE_TYPE (t)) == t) + TYPE_REFERENCE_TO (TREE_TYPE (t)) = TYPE_NEXT_REF_TO (t); + else + { + tree tem = TYPE_REFERENCE_TO (TREE_TYPE (t)); + while (tem && TYPE_NEXT_REF_TO (tem) != t) + tem = TYPE_NEXT_REF_TO (tem); + if (tem) + TYPE_NEXT_REF_TO (tem) = TYPE_NEXT_REF_TO (t); + } + TYPE_NEXT_REF_TO (t) = NULL_TREE; + } + + t = new_type; + } + else + *slot = (void *) t; + + return t; +} + + +/* Show statistics on references to the global type table gimple_types. */ + +void +print_gimple_types_stats (void) +{ + if (gimple_types) + fprintf (stderr, "GIMPLE type table: size %ld, %ld elements, " + "%ld searches, %ld collisions (ratio: %f)\n", + (long) htab_size (gimple_types), + (long) htab_elements (gimple_types), + (long) gimple_types->searches, + (long) gimple_types->collisions, + htab_collisions (gimple_types)); + else + fprintf (stderr, "GIMPLE type table is empty\n"); + if (gtc_visited) + fprintf (stderr, "GIMPLE type comparison table: size %ld, %ld " + "elements, %ld searches, %ld collisions (ratio: %f)\n", + (long) htab_size (gtc_visited), + (long) htab_elements (gtc_visited), + (long) gtc_visited->searches, + (long) gtc_visited->collisions, + htab_collisions (gtc_visited)); + else + fprintf (stderr, "GIMPLE type comparison table is empty\n"); +} + +/* Free the gimple type hashtables used for LTO type merging. */ + +void +free_gimple_type_tables (void) +{ + /* Last chance to print stats for the tables. */ + if (flag_lto_report) + print_gimple_types_stats (); + + if (gimple_types) + { + htab_delete (gimple_types); + gimple_types = NULL; + } + if (type_hash_cache) + { + pointer_map_destroy (type_hash_cache); + type_hash_cache = NULL; + } + if (gtc_visited) + { + htab_delete (gtc_visited); + obstack_free (>c_ob, NULL); + gtc_visited = NULL; + } +} + + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ + +static tree +gimple_signed_or_unsigned_type (bool unsignedp, tree type) +{ + tree type1; + + type1 = TYPE_MAIN_VARIANT (type); + if (type1 == signed_char_type_node + || type1 == char_type_node + || type1 == unsigned_char_type_node) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (type1 == integer_type_node || type1 == unsigned_type_node) + return unsignedp ? unsigned_type_node : integer_type_node; + if (type1 == short_integer_type_node || type1 == short_unsigned_type_node) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (type1 == long_integer_type_node || type1 == long_unsigned_type_node) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (type1 == long_long_integer_type_node + || type1 == long_long_unsigned_type_node) + return unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node; +#if HOST_BITS_PER_WIDE_INT >= 64 + if (type1 == intTI_type_node || type1 == unsigned_intTI_type_node) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + if (type1 == intDI_type_node || type1 == unsigned_intDI_type_node) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (type1 == intSI_type_node || type1 == unsigned_intSI_type_node) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (type1 == intHI_type_node || type1 == unsigned_intHI_type_node) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (type1 == intQI_type_node || type1 == unsigned_intQI_type_node) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + +#define GIMPLE_FIXED_TYPES(NAME) \ + if (type1 == short_ ## NAME ## _type_node \ + || type1 == unsigned_short_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_short_ ## NAME ## _type_node \ + : short_ ## NAME ## _type_node; \ + if (type1 == NAME ## _type_node \ + || type1 == unsigned_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_ ## NAME ## _type_node \ + : NAME ## _type_node; \ + if (type1 == long_ ## NAME ## _type_node \ + || type1 == unsigned_long_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_long_ ## NAME ## _type_node \ + : long_ ## NAME ## _type_node; \ + if (type1 == long_long_ ## NAME ## _type_node \ + || type1 == unsigned_long_long_ ## NAME ## _type_node) \ + return unsignedp ? unsigned_long_long_ ## NAME ## _type_node \ + : long_long_ ## NAME ## _type_node; + +#define GIMPLE_FIXED_MODE_TYPES(NAME) \ + if (type1 == NAME ## _type_node \ + || type1 == u ## NAME ## _type_node) \ + return unsignedp ? u ## NAME ## _type_node \ + : NAME ## _type_node; + +#define GIMPLE_FIXED_TYPES_SAT(NAME) \ + if (type1 == sat_ ## short_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_short_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_short_ ## NAME ## _type_node \ + : sat_ ## short_ ## NAME ## _type_node; \ + if (type1 == sat_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_ ## NAME ## _type_node \ + : sat_ ## NAME ## _type_node; \ + if (type1 == sat_ ## long_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_long_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_long_ ## NAME ## _type_node \ + : sat_ ## long_ ## NAME ## _type_node; \ + if (type1 == sat_ ## long_long_ ## NAME ## _type_node \ + || type1 == sat_ ## unsigned_long_long_ ## NAME ## _type_node) \ + return unsignedp ? sat_ ## unsigned_long_long_ ## NAME ## _type_node \ + : sat_ ## long_long_ ## NAME ## _type_node; + +#define GIMPLE_FIXED_MODE_TYPES_SAT(NAME) \ + if (type1 == sat_ ## NAME ## _type_node \ + || type1 == sat_ ## u ## NAME ## _type_node) \ + return unsignedp ? sat_ ## u ## NAME ## _type_node \ + : sat_ ## NAME ## _type_node; + + GIMPLE_FIXED_TYPES (fract); + GIMPLE_FIXED_TYPES_SAT (fract); + GIMPLE_FIXED_TYPES (accum); + GIMPLE_FIXED_TYPES_SAT (accum); + + GIMPLE_FIXED_MODE_TYPES (qq); + GIMPLE_FIXED_MODE_TYPES (hq); + GIMPLE_FIXED_MODE_TYPES (sq); + GIMPLE_FIXED_MODE_TYPES (dq); + GIMPLE_FIXED_MODE_TYPES (tq); + GIMPLE_FIXED_MODE_TYPES_SAT (qq); + GIMPLE_FIXED_MODE_TYPES_SAT (hq); + GIMPLE_FIXED_MODE_TYPES_SAT (sq); + GIMPLE_FIXED_MODE_TYPES_SAT (dq); + GIMPLE_FIXED_MODE_TYPES_SAT (tq); + GIMPLE_FIXED_MODE_TYPES (ha); + GIMPLE_FIXED_MODE_TYPES (sa); + GIMPLE_FIXED_MODE_TYPES (da); + GIMPLE_FIXED_MODE_TYPES (ta); + GIMPLE_FIXED_MODE_TYPES_SAT (ha); + GIMPLE_FIXED_MODE_TYPES_SAT (sa); + GIMPLE_FIXED_MODE_TYPES_SAT (da); + GIMPLE_FIXED_MODE_TYPES_SAT (ta); + + /* For ENUMERAL_TYPEs in C++, must check the mode of the types, not + the precision; they have precision set to match their range, but + may use a wider mode to match an ABI. If we change modes, we may + wind up with bad conversions. For INTEGER_TYPEs in C, must check + the precision as well, so as to yield correct results for + bit-field types. C++ does not have these separate bit-field + types, and producing a signed or unsigned variant of an + ENUMERAL_TYPE may cause other problems as well. */ + if (!INTEGRAL_TYPE_P (type) + || TYPE_UNSIGNED (type) == unsignedp) + return type; + +#define TYPE_OK(node) \ + (TYPE_MODE (type) == TYPE_MODE (node) \ + && TYPE_PRECISION (type) == TYPE_PRECISION (node)) + if (TYPE_OK (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + if (TYPE_OK (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + if (TYPE_OK (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + if (TYPE_OK (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + if (TYPE_OK (long_long_integer_type_node)) + return (unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node); + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (TYPE_OK (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; +#endif + if (TYPE_OK (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + if (TYPE_OK (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + if (TYPE_OK (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + if (TYPE_OK (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + +#undef GIMPLE_FIXED_TYPES +#undef GIMPLE_FIXED_MODE_TYPES +#undef GIMPLE_FIXED_TYPES_SAT +#undef GIMPLE_FIXED_MODE_TYPES_SAT +#undef TYPE_OK + + return build_nonstandard_integer_type (TYPE_PRECISION (type), unsignedp); +} + + +/* Return an unsigned type the same as TYPE in other respects. */ + +tree +gimple_unsigned_type (tree type) +{ + return gimple_signed_or_unsigned_type (true, type); +} + + +/* Return a signed type the same as TYPE in other respects. */ + +tree +gimple_signed_type (tree type) +{ + return gimple_signed_or_unsigned_type (false, type); +} + + +/* 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. */ + +alias_set_type +gimple_get_alias_set (tree t) +{ + tree u; + + /* Permit type-punning when accessing a union, provided the access + is directly through the union. For example, this code does not + permit taking the address of a union member and then storing + through it. Even the type-punning allowed here is a GCC + extension, albeit a common and useful one; the C standard says + that such accesses have implementation-defined behavior. */ + for (u = t; + TREE_CODE (u) == COMPONENT_REF || TREE_CODE (u) == ARRAY_REF; + u = TREE_OPERAND (u, 0)) + if (TREE_CODE (u) == COMPONENT_REF + && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE) + return 0; + + /* That's all the expressions we handle specially. */ + if (!TYPE_P (t)) + return -1; + + /* For convenience, follow the C standard when dealing with + character types. Any object may be accessed via an lvalue that + has character type. */ + if (t == char_type_node + || t == signed_char_type_node + || t == unsigned_char_type_node) + return 0; + + /* Allow aliasing between signed and unsigned variants of the same + type. We treat the signed variant as canonical. */ + if (TREE_CODE (t) == INTEGER_TYPE && TYPE_UNSIGNED (t)) + { + tree t1 = gimple_signed_type (t); + + /* t1 == t can happen for boolean nodes which are always unsigned. */ + if (t1 != t) + return get_alias_set (t1); + } + else if (POINTER_TYPE_P (t)) + { + /* From the common C and C++ langhook implementation: + + Unfortunately, there is no canonical form of a pointer type. + In particular, if we have `typedef int I', then `int *', and + `I *' are different types. So, we have to pick a canonical + representative. We do this below. + + Technically, this approach is actually more conservative that + it needs to be. In particular, `const int *' and `int *' + should be in different alias sets, according to the C and C++ + standard, since their types are not the same, and so, + technically, an `int **' and `const int **' cannot point at + the same thing. + + 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 + can dereference IPP and CIPP. So, we ignore cv-qualifiers on + the pointed-to types. This issue has been reported to the + C++ committee. */ + + /* In addition to the above canonicalization issue with LTO + we should also canonicalize `T (*)[]' to `T *' avoiding + alias issues with pointer-to element types and pointer-to + array types. + + Likewise we need to deal with the situation of incomplete + pointed-to types and make `*(struct X **)&a' and + `*(struct X {} **)&a' alias. Otherwise we will have to + guarantee that all pointer-to incomplete type variants + will be replaced by pointer-to complete type variants if + they are available. + + With LTO the convenient situation of using `void *' to + access and store any pointer type will also become + more apparent (and `void *' is just another pointer-to + incomplete type). Assigning alias-set zero to `void *' + and all pointer-to incomplete types is a not appealing + solution. Assigning an effective alias-set zero only + affecting pointers might be - by recording proper subset + relationships of all pointer alias-sets. + + Pointer-to function types are another grey area which + needs caution. Globbing them all into one alias-set + or the above effective zero set would work. */ + + /* For now just assign the same alias-set to all pointers. + That's simple and avoids all the above problems. */ + if (t != ptr_type_node) + return get_alias_set (ptr_type_node); + } + + return -1; +} + + /* Data structure used to count the number of dereferences to PTR inside an expression. */ struct count_ptr_d @@ -3344,7 +4575,6 @@ gimple_decl_printable_name (tree decl, int verbosity) if (verbosity >= 2) { dmgl_opts = DMGL_VERBOSE - | DMGL_TYPES | DMGL_ANSI | DMGL_GNU_V3 | DMGL_RET_POSTFIX; diff --git a/gcc/gimple.h b/gcc/gimple.h index e1e3b655b7d..8f6b3522098 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -855,6 +855,8 @@ bool gimple_assign_rhs_could_trap_p (gimple); void gimple_regimplify_operands (gimple, gimple_stmt_iterator *); bool empty_body_p (gimple_seq); unsigned get_gimple_rhs_num_ops (enum tree_code); +#define gimple_alloc(c, n) gimple_alloc_stat (c, n MEM_STAT_INFO) +gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); const char *gimple_decl_printable_name (tree, int); tree gimple_fold_obj_type_ref (tree, tree); @@ -913,6 +915,12 @@ extern bool is_gimple_call_addr (tree); extern tree get_call_expr_in (tree t); extern void recalculate_side_effects (tree); +extern tree gimple_register_type (tree); +extern void print_gimple_types_stats (void); +extern void free_gimple_type_tables (void); +extern tree gimple_unsigned_type (tree); +extern tree gimple_signed_type (tree); +extern alias_set_type gimple_get_alias_set (tree); extern void count_uses_and_derefs (tree, gimple, unsigned *, unsigned *, unsigned *); extern bool walk_stmt_load_store_addr_ops (gimple, void *, @@ -931,7 +939,6 @@ extern tree create_tmp_var (tree, const char *); extern tree get_initialized_tmp_var (tree, gimple_seq *, gimple_seq *); extern tree get_formal_tmp_var (tree, gimple_seq *); extern void declare_vars (tree, gimple, bool); -extern void tree_annotate_all_with_location (tree *, location_t); extern void annotate_all_with_location (gimple_seq, location_t); /* Validation of GIMPLE expressions. Note that these predicates only check @@ -2912,6 +2919,16 @@ gimple_eh_must_not_throw_fndecl (gimple gs) return gs->gimple_eh_mnt.fndecl; } +/* Set the function decl to be called by GS to DECL. */ + +static inline void +gimple_eh_must_not_throw_set_fndecl (gimple gs, tree decl) +{ + GIMPLE_CHECK (gs, GIMPLE_EH_MUST_NOT_THROW); + gs->gimple_eh_mnt.fndecl = decl; +} + + /* GIMPLE_TRY accessors. */ /* Return the kind of try block represented by GIMPLE_TRY GS. This is diff --git a/gcc/gimplify.c b/gcc/gimplify.c index c0cab205613..d68aacd04f3 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -777,23 +777,6 @@ should_carry_location_p (gimple gs) return true; } -/* Same, but for a tree. */ - -static bool -tree_should_carry_location_p (const_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; -} /* Return true if a location should not be emitted for this statement by annotate_one_with_location. */ @@ -826,16 +809,6 @@ annotate_one_with_location (gimple gs, location_t location) gimple_set_location (gs, location); } -/* Same, but for tree T. */ - -static void -tree_annotate_one_with_location (tree t, location_t location) -{ - if (CAN_HAVE_LOCATION_P (t) - && ! EXPR_HAS_LOCATION (t) && tree_should_carry_location_p (t)) - SET_EXPR_LOCATION (t, location); -} - /* Set LOCATION for all the statements after iterator GSI in sequence SEQ. If GSI is pointing to the end of the sequence, start with the @@ -872,29 +845,6 @@ annotate_all_with_location (gimple_seq stmt_p, location_t location) } } -/* Same, but for statement or statement list in *STMT_P. */ - -void -tree_annotate_all_with_location (tree *stmt_p, location_t location) -{ - 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); - - /* Assuming we've already been gimplified, we shouldn't - see nested chaining constructs anymore. */ - gcc_assert (TREE_CODE (t) != STATEMENT_LIST - && TREE_CODE (t) != COMPOUND_EXPR); - - tree_annotate_one_with_location (t, location); - } -} - /* 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 diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c index ccf539eb0dc..2eb50df2575 100644 --- a/gcc/graphite-sese-to-poly.c +++ b/gcc/graphite-sese-to-poly.c @@ -2084,7 +2084,7 @@ build_poly_scop (scop_p scop) /* Always return false. Exercise the scop_to_clast function. */ void -check_poly_representation (scop_p scop) +check_poly_representation (scop_p scop ATTRIBUTE_UNUSED) { #ifdef ENABLE_CHECKING cloog_prog_clast pc = scop_to_clast (scop); diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c index dc0791f6f2f..7cbe1ecee51 100644 --- a/gcc/haifa-sched.c +++ b/gcc/haifa-sched.c @@ -989,7 +989,7 @@ dep_list_size (rtx insn) { if (DEBUG_INSN_P (DEP_CON (dep))) dbgcount++; - else + else if (!DEBUG_INSN_P (DEP_PRO (dep))) nodbgcount++; } @@ -1688,6 +1688,39 @@ schedule_insn (rtx insn) should have been removed from the ready list. */ gcc_assert (sd_lists_empty_p (insn, SD_LIST_BACK)); + /* Reset debug insns invalidated by moving this insn. */ + if (MAY_HAVE_DEBUG_INSNS && !DEBUG_INSN_P (insn)) + for (sd_it = sd_iterator_start (insn, SD_LIST_BACK); + sd_iterator_cond (&sd_it, &dep);) + { + rtx dbg = DEP_PRO (dep); + + gcc_assert (DEBUG_INSN_P (dbg)); + + if (sched_verbose >= 6) + fprintf (sched_dump, ";;\t\tresetting: debug insn %d\n", + INSN_UID (dbg)); + + /* ??? Rather than resetting the debug insn, we might be able + to emit a debug temp before the just-scheduled insn, but + this would involve checking that the expression at the + point of the debug insn is equivalent to the expression + before the just-scheduled insn. They might not be: the + expression in the debug insn may depend on other insns not + yet scheduled that set MEMs, REGs or even other debug + insns. It's not clear that attempting to preserve debug + information in these cases is worth the effort, given how + uncommon these resets are and the likelihood that the debug + temps introduced won't survive the schedule change. */ + INSN_VAR_LOCATION_LOC (dbg) = gen_rtx_UNKNOWN_VAR_LOC (); + df_insn_rescan (dbg); + + /* We delete rather than resolve these deps, otherwise we + crash in sched_free_deps(), because forward deps are + expected to be released before backward deps. */ + sd_delete_dep (sd_it); + } + gcc_assert (QUEUE_INDEX (insn) == QUEUE_NOWHERE); QUEUE_INDEX (insn) = QUEUE_SCHEDULED; @@ -1712,6 +1745,12 @@ schedule_insn (rtx insn) advancing the iterator. */ sd_resolve_dep (sd_it); + /* Don't bother trying to mark next as ready if insn is a debug + insn. If insn is the last hard dependency, it will have + already been discounted. */ + if (DEBUG_INSN_P (insn) && !DEBUG_INSN_P (next)) + continue; + if (!IS_SPECULATION_BRANCHY_CHECK_P (insn)) { int effective_cost; @@ -3715,6 +3754,10 @@ try_ready (rtx next) { ds_t ds = DEP_STATUS (dep) & SPECULATIVE; + if (DEBUG_INSN_P (DEP_PRO (dep)) + && !DEBUG_INSN_P (next)) + continue; + if (first_p) { first_p = false; diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c index 1ef2d21f903..4417e6e6b87 100644 --- a/gcc/ifcvt.c +++ b/gcc/ifcvt.c @@ -47,9 +47,6 @@ #include "vecprim.h" #include "dbgcnt.h" -#ifndef HAVE_conditional_execution -#define HAVE_conditional_execution 0 -#endif #ifndef HAVE_conditional_move #define HAVE_conditional_move 0 #endif @@ -1329,11 +1326,15 @@ noce_try_cmove_arith (struct noce_if_info *if_info) /* ??? FIXME: Magic number 5. */ if (cse_not_expected && MEM_P (a) && MEM_P (b) + && MEM_ADDR_SPACE (a) == MEM_ADDR_SPACE (b) && if_info->branch_cost >= 5) { + enum machine_mode address_mode + = targetm.addr_space.address_mode (MEM_ADDR_SPACE (a)); + a = XEXP (a, 0); b = XEXP (b, 0); - x = gen_reg_rtx (Pmode); + x = gen_reg_rtx (address_mode); is_mem = 1; } @@ -1482,6 +1483,9 @@ noce_try_cmove_arith (struct noce_if_info *if_info) set_mem_align (tmp, MIN (MEM_ALIGN (if_info->a), MEM_ALIGN (if_info->b))); + gcc_assert (MEM_ADDR_SPACE (if_info->a) == MEM_ADDR_SPACE (if_info->b)); + set_mem_addr_space (tmp, MEM_ADDR_SPACE (if_info->a)); + noce_emit_move_insn (if_info->x, tmp); } else if (target != x) @@ -2419,7 +2423,7 @@ noce_process_if_block (struct noce_if_info *if_info) if (HAVE_conditional_move && noce_try_cmove (if_info)) goto success; - if (! HAVE_conditional_execution) + if (! targetm.have_conditional_execution ()) { if (noce_try_store_flag_constants (if_info)) goto success; @@ -3063,7 +3067,7 @@ find_if_header (basic_block test_bb, int pass) && noce_find_if_block (test_bb, then_edge, else_edge, pass)) goto success; - if (HAVE_conditional_execution && reload_completed + if (targetm.have_conditional_execution () && reload_completed && cond_exec_find_if_block (&ce_info)) goto success; @@ -3073,7 +3077,7 @@ find_if_header (basic_block test_bb, int pass) goto success; if (dom_info_state (CDI_POST_DOMINATORS) >= DOM_NO_FAST_QUERY - && (! HAVE_conditional_execution || reload_completed)) + && (! targetm.have_conditional_execution () || reload_completed)) { if (find_if_case_1 (test_bb, then_edge, else_edge)) goto success; @@ -3180,7 +3184,7 @@ cond_exec_find_if_block (struct ce_if_block * ce_info) /* We only ever should get here after reload, and only if we have conditional execution. */ - gcc_assert (HAVE_conditional_execution && reload_completed); + gcc_assert (targetm.have_conditional_execution () && reload_completed); /* Discover if any fall through predecessors of the current test basic block were && tests (which jump to the else block) or || tests (which jump to @@ -3858,7 +3862,7 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb, /* Disable handling dead code by conditional execution if the machine needs to do anything funny with the tests, etc. */ #ifndef IFCVT_MODIFY_TESTS - if (HAVE_conditional_execution) + if (targetm.have_conditional_execution ()) { /* In the conditional execution case, we have things easy. We know the condition is reversible. We don't have to check life info diff --git a/gcc/input.h b/gcc/input.h index 299f56c3ce6..7f00dc7cd0a 100644 --- a/gcc/input.h +++ b/gcc/input.h @@ -1,6 +1,6 @@ /* Declarations for variables relating to reading the source file. Used by parsers, lexical analyzers, and error message routines. - Copyright (C) 1993, 1997, 1998, 2000, 2003, 2004, 2007, 2008 + Copyright (C) 1993, 1997, 1998, 2000, 2003, 2004, 2007, 2008, 2009 Free Software Foundation, Inc. This file is part of GCC. @@ -30,7 +30,12 @@ extern GTY(()) struct line_maps *line_table; #define UNKNOWN_LOCATION ((source_location) 0) /* The location for declarations in "" */ -#define BUILTINS_LOCATION ((source_location) 2) +#define BUILTINS_LOCATION ((source_location) 1) + +/* line-map.c reserves RESERVED_LOCATION_COUNT to the user. Ensure + both UNKNOWN_LOCATION and BUILTINS_LOCATION fit into that. */ +extern char builtins_location_check[(BUILTINS_LOCATION + < RESERVED_LOCATION_COUNT) ? 1 : -1]; typedef struct GTY (()) { diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index f7782cbbf83..79ff16e0e7f 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -299,9 +299,16 @@ ipcp_lattice_from_jfunc (struct ipa_node_params *info, struct ipcp_lattice *lat, cst = caller_lat->constant; if (jfunc->value.pass_through.operation != NOP_EXPR) - cst = fold_binary (jfunc->value.pass_through.operation, - TREE_TYPE (cst), cst, - jfunc->value.pass_through.operand); + { + tree restype; + if (TREE_CODE_CLASS (jfunc->value.pass_through.operation) + == tcc_comparison) + restype = boolean_type_node; + else + restype = TREE_TYPE (cst); + cst = fold_binary (jfunc->value.pass_through.operation, + restype, cst, jfunc->value.pass_through.operand); + } if (!cst || !is_gimple_ip_invariant (cst)) lat->type = IPA_BOTTOM; lat->constant = cst; @@ -442,7 +449,7 @@ ipcp_cloning_candidate_p (struct cgraph_node *node) FIXME: in future we should clone such functions when they are called with different constants, but current ipcp implementation is not good on this. */ - if (!node->needed || !node->analyzed) + if (cgraph_only_called_directly_p (node) || !node->analyzed) return false; if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) @@ -536,7 +543,7 @@ ipcp_initialize_node_lattices (struct cgraph_node *node) if (ipa_is_called_with_var_arguments (info)) type = IPA_BOTTOM; - else if (!node->needed) + else if (cgraph_only_called_directly_p (node)) type = IPA_TOP; /* When cloning is allowed, we can assume that externally visible functions are not called. We will compensate this by cloning later. */ @@ -607,7 +614,9 @@ ipcp_init_stage (void) /* building jump functions */ for (cs = node->callees; cs; cs = cs->next_callee) { - if (!cs->callee->analyzed) + /* We do not need to bother analyzing calls to unknown + functions unless they may become known during lto/whopr. */ + if (!cs->callee->analyzed && !flag_lto && !flag_whopr) continue; ipa_count_arguments (cs); if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs)) @@ -689,7 +698,9 @@ ipcp_propagate_stage (void) struct ipa_node_params *callee_info = IPA_NODE_REF (cs->callee); struct ipa_edge_args *args = IPA_EDGE_REF (cs); - if (ipa_is_called_with_var_arguments (callee_info)) + if (ipa_is_called_with_var_arguments (callee_info) + || !cs->callee->analyzed + || ipa_is_called_with_var_arguments (callee_info)) continue; count = ipa_get_cs_argument_count (args); @@ -720,6 +731,10 @@ ipcp_iterate_stage (void) if (dump_file) fprintf (dump_file, "\nIPA iterate stage:\n\n"); + + if (in_lto_p) + ipa_update_after_lto_read (); + for (node = cgraph_nodes; node; node = node->next) { ipcp_initialize_node_lattices (node); @@ -954,7 +969,7 @@ ipcp_estimate_growth (struct cgraph_node *node) struct cgraph_edge *cs; int redirectable_node_callers = 0; int removable_args = 0; - bool need_original = node->needed; + bool need_original = !cgraph_only_called_directly_p (node); struct ipa_node_params *info; int i, count; int growth; @@ -1143,7 +1158,7 @@ ipcp_insert_stage (void) for (cs = node->callers; cs != NULL; cs = cs->next_caller) if (cs->caller == node || ipcp_need_redirect_p (cs)) break; - if (!cs && !node->needed) + if (!cs && cgraph_only_called_directly_p (node)) bitmap_set_bit (dead_nodes, node->uid); info = IPA_NODE_REF (node); @@ -1269,6 +1284,20 @@ ipcp_generate_summary (void) ipcp_init_stage (); } +/* Write ipcp summary for nodes in SET. */ +static void +ipcp_write_summary (cgraph_node_set set) +{ + ipa_prop_write_jump_functions (set); +} + +/* Read ipcp summary. */ +static void +ipcp_read_summary (void) +{ + ipa_prop_read_jump_functions (); +} + /* Gate for IPCP optimization. */ static bool cgraph_gate_cp (void) @@ -1295,8 +1324,8 @@ struct ipa_opt_pass_d pass_ipa_cp = TODO_remove_functions /* todo_flags_finish */ }, ipcp_generate_summary, /* generate_summary */ - NULL, /* write_summary */ - NULL, /* read_summary */ + ipcp_write_summary, /* write_summary */ + ipcp_read_summary, /* read_summary */ NULL, /* function_read_summary */ 0, /* TODOs */ NULL, /* function_transform */ diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c index 8851d605372..bc7048f51c6 100644 --- a/gcc/ipa-inline.c +++ b/gcc/ipa-inline.c @@ -223,7 +223,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, /* We may eliminate the need for out-of-line copy to be output. In that case just go ahead and re-use it. */ if (!e->callee->callers->next_caller - && !e->callee->needed + && cgraph_can_remove_if_no_direct_calls_p (e->callee) && !cgraph_new_nodes) { gcc_assert (!e->callee->global.inlined_to); @@ -233,6 +233,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, nfunctions_inlined++; } duplicate = false; + e->callee->local.externally_visible = false; } else { @@ -286,7 +287,7 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original, e->callee->global.inlined = true; if (e->callee->callers->next_caller - || e->callee->needed) + || !cgraph_can_remove_if_no_direct_calls_p (e->callee)) duplicate = true; cgraph_clone_inlined_nodes (e, true, update_original); @@ -309,7 +310,7 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original, overall_size -= orig_size; ncalls_inlined++; - if (flag_indirect_inlining) + if (flag_indirect_inlining && !flag_wpa) return ipa_propagate_indirect_call_infos (curr, new_edges); else return false; @@ -326,7 +327,7 @@ cgraph_mark_inline (struct cgraph_edge *edge) struct cgraph_node *what = edge->callee; struct cgraph_edge *e, *next; - gcc_assert (!gimple_call_cannot_inline_p (edge->call_stmt)); + gcc_assert (!edge->call_stmt_cannot_inline_p); /* Look for all calls, mark them inline and clone recursively all inlined functions. */ for (e = what->callers; e; e = next) @@ -368,7 +369,8 @@ cgraph_estimate_growth (struct cgraph_node *node) 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 && !DECL_EXTERNAL (node->decl) && !self_recursive) + if (cgraph_only_called_directly_p (node) + && !DECL_EXTERNAL (node->decl) && !self_recursive) growth -= node->global.size; node->global.estimated_growth = growth; @@ -874,7 +876,7 @@ cgraph_decide_inlining_of_small_functions (void) int min_size, max_size; VEC (cgraph_edge_p, heap) *new_indirect_edges = NULL; - if (flag_indirect_inlining) + if (flag_indirect_inlining && !flag_wpa) new_indirect_edges = VEC_alloc (cgraph_edge_p, heap, 8); if (dump_file) @@ -1021,17 +1023,17 @@ cgraph_decide_inlining_of_small_functions (void) if (where->global.inlined_to) where = where->global.inlined_to; if (!cgraph_decide_recursive_inlining (where, - flag_indirect_inlining + flag_indirect_inlining && !flag_wpa ? &new_indirect_edges : NULL)) continue; - if (flag_indirect_inlining) + if (flag_indirect_inlining && !flag_wpa) add_new_edges_to_heap (heap, new_indirect_edges); update_callee_keys (heap, where, updated_nodes); } else { struct cgraph_node *callee; - if (gimple_call_cannot_inline_p (edge->call_stmt) + if (edge->call_stmt_cannot_inline_p || !cgraph_check_inline_limits (edge->caller, edge->callee, &edge->inline_failed, true)) { @@ -1043,7 +1045,7 @@ cgraph_decide_inlining_of_small_functions (void) } callee = edge->callee; cgraph_mark_inline_edge (edge, true, &new_indirect_edges); - if (flag_indirect_inlining) + if (flag_indirect_inlining && !flag_wpa) add_new_edges_to_heap (heap, new_indirect_edges); update_callee_keys (heap, callee, updated_nodes); @@ -1112,6 +1114,8 @@ cgraph_decide_inlining (void) int initial_size = 0; cgraph_remove_function_insertion_hook (function_insertion_hook_holder); + if (in_lto_p && flag_indirect_inlining && !flag_wpa) + ipa_update_after_lto_read (); max_count = 0; max_benefit = 0; @@ -1121,7 +1125,6 @@ cgraph_decide_inlining (void) struct cgraph_edge *e; gcc_assert (inline_summary (node)->self_size == node->global.size); - gcc_assert (node->needed || node->reachable); initial_size += node->global.size; for (e = node->callees; e; e = e->next_callee) if (max_count < e->count) @@ -1129,7 +1132,9 @@ cgraph_decide_inlining (void) if (max_benefit < inline_summary (node)->time_inlining_benefit) max_benefit = inline_summary (node)->time_inlining_benefit; } - gcc_assert (!max_count || (profile_info && flag_branch_probabilities)); + gcc_assert (in_lto_p + || !max_count + || (profile_info && flag_branch_probabilities)); overall_size = initial_size; nnodes = cgraph_postorder (order); @@ -1177,8 +1182,7 @@ cgraph_decide_inlining (void) for (e = node->callers; e; e = next) { next = e->next_caller; - if (!e->inline_failed - || gimple_call_cannot_inline_p (e->call_stmt)) + if (!e->inline_failed || e->call_stmt_cannot_inline_p) continue; if (cgraph_recursive_inlining_p (e->caller, e->callee, &e->inline_failed)) @@ -1220,15 +1224,16 @@ cgraph_decide_inlining (void) if (node->callers && !node->callers->next_caller - && !node->needed + && cgraph_only_called_directly_p (node) && node->local.inlinable && node->callers->inline_failed && node->callers->caller != node && node->callers->caller->global.inlined_to != node - && !gimple_call_cannot_inline_p (node->callers->call_stmt) + && !node->callers->call_stmt_cannot_inline_p && !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl)) { + cgraph_inline_failed_t reason; old_size = overall_size; if (dump_file) { @@ -1242,7 +1247,7 @@ cgraph_decide_inlining (void) } if (cgraph_check_inline_limits (node->callers->caller, node, - NULL, false)) + &reason, false)) { cgraph_mark_inline (node->callers); if (dump_file) @@ -1257,14 +1262,15 @@ cgraph_decide_inlining (void) { if (dump_file) fprintf (dump_file, - " Inline limit reached, not inlined.\n"); + " Not inlining: %s.\n", + cgraph_inline_failed_string (reason)); } } } } /* Free ipa-prop structures if they are no longer needed. */ - if (flag_indirect_inlining) + if (flag_indirect_inlining && !flag_wpa) free_all_ipa_structures_after_iinln (); if (dump_file) @@ -1411,7 +1417,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, if (!e->callee->local.disregard_inline_limits && (mode != INLINE_ALL || !e->callee->local.inlinable)) continue; - if (gimple_call_cannot_inline_p (e->call_stmt)) + if (e->call_stmt_cannot_inline_p) continue; /* When the edge is already inlined, we just need to recurse into it in order to fully flatten the leaves. */ @@ -1529,7 +1535,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node, } if (!cgraph_check_inline_limits (node, e->callee, &e->inline_failed, false) - || gimple_call_cannot_inline_p (e->call_stmt)) + || e->call_stmt_cannot_inline_p) { if (dump_file) { @@ -1585,10 +1591,10 @@ cgraph_early_inlining (void) if (sorrycount || errorcount) return 0; - while (cgraph_decide_inlining_incrementally (node, - iterations - ? INLINE_SIZE_NORECURSIVE : INLINE_SIZE, 0) - && iterations < PARAM_VALUE (PARAM_EARLY_INLINER_MAX_ITERATIONS)) + while (iterations < PARAM_VALUE (PARAM_EARLY_INLINER_MAX_ITERATIONS) + && cgraph_decide_inlining_incrementally (node, + iterations + ? INLINE_SIZE_NORECURSIVE : INLINE_SIZE, 0)) { timevar_push (TV_INTEGRATION); todo |= optimize_inline_calls (current_function_decl); @@ -1632,6 +1638,7 @@ static bool cgraph_gate_ipa_early_inlining (void) { return (flag_early_inlining + && !in_lto_p && (flag_branch_probabilities || flag_test_coverage || profile_arc_flag)); } @@ -1963,6 +1970,34 @@ inline_transform (struct cgraph_node *node) return todo | execute_fixup_cfg (); } +/* Read inline summary. Jump functions are shared among ipa-cp + and inliner, so when ipa-cp is active, we don't need to write them + twice. */ + +static void +inline_read_summary (void) +{ + if (flag_indirect_inlining && !flag_wpa) + { + ipa_register_cgraph_hooks (); + if (!flag_ipa_cp) + ipa_prop_read_jump_functions (); + } + function_insertion_hook_holder = + cgraph_add_function_insertion_hook (&add_new_function, NULL); +} + +/* Write inline summary for node in SET. + Jump functions are shared among ipa-cp and inliner, so when ipa-cp is + active, we don't need to write them twice. */ + +static void +inline_write_summary (cgraph_node_set set) +{ + if (flag_indirect_inlining && !flag_ipa_cp) + ipa_prop_write_jump_functions (set); +} + struct ipa_opt_pass_d pass_ipa_inline = { { @@ -1982,8 +2017,8 @@ struct ipa_opt_pass_d pass_ipa_inline = | TODO_remove_functions /* todo_flags_finish */ }, inline_generate_summary, /* generate_summary */ - NULL, /* write_summary */ - NULL, /* read_summary */ + inline_write_summary, /* write_summary */ + inline_read_summary, /* read_summary */ NULL, /* function_read_summary */ 0, /* TODOs */ inline_transform, /* function_transform */ diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 23710067ee7..9956fbc53b7 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -33,11 +33,12 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "flags.h" #include "diagnostic.h" +#include "lto-streamer.h" /* Vector where the parameter infos are actually stored. */ VEC (ipa_node_params_t, heap) *ipa_node_params_vector; /* Vector where the parameter infos are actually stored. */ -VEC (ipa_edge_args_t, heap) *ipa_edge_args_vector; +VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector; /* Holders of ipa cgraph hooks: */ static struct cgraph_edge_hook_list *edge_removal_hook_holder; @@ -248,7 +249,7 @@ ipa_count_arguments (struct cgraph_edge *cs) arg_num = gimple_call_num_args (stmt); if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector) <= (unsigned) cgraph_edge_max_uid) - VEC_safe_grow_cleared (ipa_edge_args_t, heap, + VEC_safe_grow_cleared (ipa_edge_args_t, gc, ipa_edge_args_vector, cgraph_edge_max_uid + 1); ipa_set_cs_argument_count (IPA_EDGE_REF (cs), arg_num); } @@ -357,6 +358,9 @@ compute_complex_pass_through (struct ipa_node_params *info, { if (TREE_CODE (op1) != SSA_NAME || !SSA_NAME_IS_DEFAULT_DEF (op1) + || (TREE_CODE_CLASS (gimple_expr_code (stmt)) != tcc_comparison + && !useless_type_conversion_p (TREE_TYPE (name), + TREE_TYPE (op1))) || !is_gimple_ip_invariant (op2)) return; @@ -658,8 +662,8 @@ ipa_compute_jump_functions (struct cgraph_edge *cs) if (ipa_get_cs_argument_count (arguments) == 0 || arguments->jump_functions) return; - arguments->jump_functions = XCNEWVEC (struct ipa_jump_func, - ipa_get_cs_argument_count (arguments)); + arguments->jump_functions = GGC_CNEWVEC (struct ipa_jump_func, + ipa_get_cs_argument_count (arguments)); call = cs->call_stmt; gcc_assert (is_gimple_call (call)); @@ -1150,6 +1154,10 @@ bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, VEC (cgraph_edge_p, heap) **new_edges) { + /* FIXME lto: We do not stream out indirect call information. */ + if (flag_wpa) + return false; + /* Do nothing if the preparation phase has not been carried out yet (i.e. during early inlining). */ if (!ipa_node_params_vector) @@ -1166,7 +1174,7 @@ void ipa_free_edge_args_substructures (struct ipa_edge_args *args) { if (args->jump_functions) - free (args->jump_functions); + ggc_free (args->jump_functions); memset (args, 0, sizeof (*args)); } @@ -1184,7 +1192,7 @@ ipa_free_all_edge_args (void) i++) ipa_free_edge_args_substructures (args); - VEC_free (ipa_edge_args_t, heap, ipa_edge_args_vector); + VEC_free (ipa_edge_args_t, gc, ipa_edge_args_vector); ipa_edge_args_vector = NULL; } @@ -1255,7 +1263,22 @@ duplicate_array (void *src, size_t n) if (!src) return NULL; - p = xcalloc (1, n); + p = xmalloc (n); + memcpy (p, src, n); + return p; +} + +/* Like duplicate_array byt in GGC memory. */ + +static void * +duplicate_ggc_array (void *src, size_t n) +{ + void *p; + + if (!src) + return NULL; + + p = ggc_alloc (n); memcpy (p, src, n); return p; } @@ -1277,8 +1300,8 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst, arg_count = ipa_get_cs_argument_count (old_args); ipa_set_cs_argument_count (new_args, arg_count); new_args->jump_functions = (struct ipa_jump_func *) - duplicate_array (old_args->jump_functions, - sizeof (struct ipa_jump_func) * arg_count); + duplicate_ggc_array (old_args->jump_functions, + sizeof (struct ipa_jump_func) * arg_count); } /* Hook that is called by cgraph.c when a node is duplicated. */ @@ -1394,7 +1417,9 @@ ipa_print_node_params (FILE * f, struct cgraph_node *node) temp = ipa_get_param (info, i); if (TREE_CODE (temp) == PARM_DECL) fprintf (f, " param %d : %s", i, - (*lang_hooks.decl_printable_name) (temp, 2)); + (DECL_NAME (temp) + ? (*lang_hooks.decl_printable_name) (temp, 2) + : "(unnamed)")); if (ipa_is_param_modified (info, i)) fprintf (f, " modified"); if (ipa_is_param_called (info, i)) @@ -1866,3 +1891,283 @@ ipa_dump_param_adjustments (FILE *file, ipa_parm_adjustment_vec adjustments, VEC_free (tree, heap, parms); } +/* Stream out jump function JUMP_FUNC to OB. */ + +static void +ipa_write_jump_function (struct output_block *ob, + struct ipa_jump_func *jump_func) +{ + lto_output_uleb128_stream (ob->main_stream, + jump_func->type); + + switch (jump_func->type) + { + case IPA_JF_UNKNOWN: + break; + case IPA_JF_CONST: + lto_output_tree (ob, jump_func->value.constant, true); + break; + case IPA_JF_PASS_THROUGH: + lto_output_tree (ob, jump_func->value.pass_through.operand, true); + lto_output_uleb128_stream (ob->main_stream, + jump_func->value.pass_through.formal_id); + lto_output_uleb128_stream (ob->main_stream, + jump_func->value.pass_through.operation); + break; + case IPA_JF_ANCESTOR: + lto_output_uleb128_stream (ob->main_stream, + jump_func->value.ancestor.offset); + lto_output_tree (ob, jump_func->value.ancestor.type, true); + lto_output_uleb128_stream (ob->main_stream, + jump_func->value.ancestor.formal_id); + break; + case IPA_JF_CONST_MEMBER_PTR: + lto_output_tree (ob, jump_func->value.member_cst.pfn, true); + lto_output_tree (ob, jump_func->value.member_cst.delta, false); + break; + } +} + +/* Read in jump function JUMP_FUNC from IB. */ + +static void +ipa_read_jump_function (struct lto_input_block *ib, + struct ipa_jump_func *jump_func, + struct data_in *data_in) +{ + jump_func->type = (enum jump_func_type) lto_input_uleb128 (ib); + + switch (jump_func->type) + { + case IPA_JF_UNKNOWN: + break; + case IPA_JF_CONST: + jump_func->value.constant = lto_input_tree (ib, data_in); + break; + case IPA_JF_PASS_THROUGH: + jump_func->value.pass_through.operand = lto_input_tree (ib, data_in); + jump_func->value.pass_through.formal_id = lto_input_uleb128 (ib); + jump_func->value.pass_through.operation = (enum tree_code) lto_input_uleb128 (ib); + break; + case IPA_JF_ANCESTOR: + jump_func->value.ancestor.offset = lto_input_uleb128 (ib); + jump_func->value.ancestor.type = lto_input_tree (ib, data_in); + jump_func->value.ancestor.formal_id = lto_input_uleb128 (ib); + break; + case IPA_JF_CONST_MEMBER_PTR: + jump_func->value.member_cst.pfn = lto_input_tree (ib, data_in); + jump_func->value.member_cst.delta = lto_input_tree (ib, data_in); + break; + } +} + +/* Stream out NODE info to OB. */ + +static void +ipa_write_node_info (struct output_block *ob, struct cgraph_node *node) +{ + int node_ref; + lto_cgraph_encoder_t encoder; + struct ipa_node_params *info = IPA_NODE_REF (node); + int j; + struct cgraph_edge *e; + struct bitpack_d *bp; + + encoder = ob->decl_state->cgraph_node_encoder; + node_ref = lto_cgraph_encoder_encode (encoder, node); + lto_output_uleb128_stream (ob->main_stream, node_ref); + + /* Note that flags will need to be read in the opposite + order as we are pushing the bitflags into FLAGS. */ + bp = bitpack_create (); + bp_pack_value (bp, info->called_with_var_arguments, 1); + gcc_assert (info->modification_analysis_done || ipa_get_param_count (info) == 0); + gcc_assert (info->uses_analysis_done || ipa_get_param_count (info) == 0); + gcc_assert (!info->node_enqueued); + gcc_assert (!info->ipcp_orig_node); + for (j = 0; j < ipa_get_param_count (info); j++) + { + bp_pack_value (bp, info->params[j].modified, 1); + bp_pack_value (bp, info->params[j].called, 1); + } + lto_output_bitpack (ob->main_stream, bp); + bitpack_delete (bp); + for (e = node->callees; e; e = e->next_callee) + { + struct ipa_edge_args *args = IPA_EDGE_REF (e); + + lto_output_uleb128_stream (ob->main_stream, ipa_get_cs_argument_count (args)); + for (j = 0; j < ipa_get_cs_argument_count (args); j++) + ipa_write_jump_function (ob, ipa_get_ith_jump_func (args, j)); + } +} + +/* Srtream in NODE info from IB. */ + +static void +ipa_read_node_info (struct lto_input_block *ib, struct cgraph_node *node, + struct data_in *data_in) +{ + struct ipa_node_params *info = IPA_NODE_REF (node); + int k; + struct cgraph_edge *e; + struct bitpack_d *bp; + + ipa_initialize_node_params (node); + + /* Note that the flags must be read in the opposite + order in which they were written (the bitflags were + pushed into FLAGS). */ + bp = lto_input_bitpack (ib); + info->called_with_var_arguments = bp_unpack_value (bp, 1); + if (ipa_get_param_count (info) != 0) + { + info->modification_analysis_done = true; + info->uses_analysis_done = true; + } + info->node_enqueued = false; + for (k = 0; k < ipa_get_param_count (info); k++) + { + info->params[k].modified = bp_unpack_value (bp, 1); + info->params[k].called = bp_unpack_value (bp, 1); + } + bitpack_delete (bp); + for (e = node->callees; e; e = e->next_callee) + { + struct ipa_edge_args *args = IPA_EDGE_REF (e); + int count = lto_input_uleb128 (ib); + + if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector) + <= (unsigned) cgraph_edge_max_uid) + VEC_safe_grow_cleared (ipa_edge_args_t, gc, + ipa_edge_args_vector, cgraph_edge_max_uid + 1); + ipa_set_cs_argument_count (args, count); + if (!count) + continue; + + args->jump_functions = GGC_CNEWVEC (struct ipa_jump_func, + ipa_get_cs_argument_count (args)); + for (k = 0; k < ipa_get_cs_argument_count (args); k++) + ipa_read_jump_function (ib, ipa_get_ith_jump_func (args, k), data_in); + } +} + +/* Write jump functions for nodes in SET. */ + +void +ipa_prop_write_jump_functions (cgraph_node_set set) +{ + struct cgraph_node *node; + struct output_block *ob = create_output_block (LTO_section_jump_functions); + unsigned int count = 0; + cgraph_node_set_iterator csi; + + ob->cgraph_node = NULL; + + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (node->analyzed && IPA_NODE_REF (node) != NULL) + count++; + } + + lto_output_uleb128_stream (ob->main_stream, count); + + /* Process all of the functions. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (node->analyzed && IPA_NODE_REF (node) != NULL) + ipa_write_node_info (ob, node); + } + lto_output_1_stream (ob->main_stream, 0); + produce_asm (ob, NULL); + destroy_output_block (ob); +} + +/* Read section in file FILE_DATA of length LEN with data DATA. */ + +static void +ipa_prop_read_section (struct lto_file_decl_data *file_data, const char *data, + size_t len) +{ + const struct lto_function_header *header = + (const struct lto_function_header *) data; + const int32_t cfg_offset = sizeof (struct lto_function_header); + const int32_t main_offset = cfg_offset + header->cfg_size; + const int32_t string_offset = main_offset + header->main_size; + struct data_in *data_in; + struct lto_input_block ib_main; + unsigned int i; + unsigned int count; + + LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0, + header->main_size); + + data_in = + lto_data_in_create (file_data, (const char *) data + string_offset, + header->string_size, NULL); + count = lto_input_uleb128 (&ib_main); + + for (i = 0; i < count; i++) + { + unsigned int index; + struct cgraph_node *node; + lto_cgraph_encoder_t encoder; + + index = lto_input_uleb128 (&ib_main); + encoder = file_data->cgraph_node_encoder; + node = lto_cgraph_encoder_deref (encoder, index); + ipa_read_node_info (&ib_main, node, data_in); + } + lto_free_section_data (file_data, LTO_section_jump_functions, NULL, data, + len); + lto_data_in_delete (data_in); +} + +/* Read ipcp jump functions. */ + +void +ipa_prop_read_jump_functions (void) +{ + struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); + struct lto_file_decl_data *file_data; + unsigned int j = 0; + + ipa_check_create_node_params (); + ipa_check_create_edge_args (); + ipa_register_cgraph_hooks (); + + while ((file_data = file_data_vec[j++])) + { + size_t len; + const char *data = lto_get_section_data (file_data, LTO_section_jump_functions, NULL, &len); + + if (data) + ipa_prop_read_section (file_data, data, len); + } +} + +/* After merging units, we can get mismatch in argument counts. + Also decl merging might've rendered parameter lists obsolette. + Also compute called_with_variable_arg info. */ + +void +ipa_update_after_lto_read (void) +{ + struct cgraph_node *node; + struct cgraph_edge *cs; + + for (node = cgraph_nodes; node; node = node->next) + { + if (!node->analyzed) + continue; + ipa_populate_param_decls (node, IPA_NODE_REF (node)); + for (cs = node->callees; cs; cs = cs->next_callee) + { + if (ipa_get_cs_argument_count (IPA_EDGE_REF (cs)) + != ipa_get_param_count (IPA_NODE_REF (cs->callee))) + ipa_set_called_with_variable_arg (IPA_NODE_REF (cs->callee)); + } + } +} diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 9b5f74f87ad..35005954deb 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -72,7 +72,7 @@ enum ipa_lattice_type /* Structure holding data required to describe a pass-through jump function. */ -struct ipa_pass_through_data +struct GTY(()) ipa_pass_through_data { /* If an operation is to be performed on the original parameter, this is the second (constant) operand. */ @@ -89,7 +89,7 @@ struct ipa_pass_through_data /* Structure holding data required to describe and ancestor pass throu funkci. */ -struct ipa_ancestor_jf_data +struct GTY(()) ipa_ancestor_jf_data { /* Offset of the field representing the ancestor. */ HOST_WIDE_INT offset; @@ -101,30 +101,28 @@ struct ipa_ancestor_jf_data /* Structure holding a C++ member pointer constant. Holds a pointer to the method and delta offset. */ -struct ipa_member_ptr_cst +struct GTY(()) ipa_member_ptr_cst { tree pfn; tree delta; }; -/* Represents a value of a jump function. pass_through is used only in jump - function context. constant represents the actual constant in constant jump - functions and member_cst holds constant c++ member functions. */ -union jump_func_value -{ - tree constant; - struct ipa_pass_through_data pass_through; - struct ipa_ancestor_jf_data ancestor; - struct ipa_member_ptr_cst member_cst; -}; - /* A jump function for a callsite represents the values passed as actual arguments of the callsite. See enum jump_func_type for the various types of jump functions supported. */ -struct ipa_jump_func +struct GTY (()) ipa_jump_func { enum jump_func_type type; - union jump_func_value value; + /* Represents a value of a jump function. pass_through is used only in jump + function context. constant represents the actual constant in constant jump + functions and member_cst holds constant c++ member functions. */ + union jump_func_value + { + tree GTY ((tag ("IPA_JF_CONST"))) constant; + struct ipa_pass_through_data GTY ((tag ("IPA_JF_PASS_THROUGH"))) pass_through; + struct ipa_ancestor_jf_data GTY ((tag ("IPA_JF_ANCESTOR"))) ancestor; + struct ipa_member_ptr_cst GTY ((tag ("IPA_JF_CONST_MEMBER_PTR"))) member_cst; + } GTY ((desc ("%1.type"))) value; }; /* All formal parameters in the program have a cval computed by @@ -280,15 +278,15 @@ ipa_is_called_with_var_arguments (struct ipa_node_params *info) /* ipa_edge_args stores information related to a callsite and particularly its arguments. It is pointed to by a field in the callsite's corresponding cgraph_edge. */ -struct ipa_edge_args +typedef struct GTY(()) ipa_edge_args { /* Number of actual arguments in this callsite. When set to 0, this callsite's parameters would not be analyzed by the different stages of IPA CP. */ int argument_count; /* Array of the callsite's jump function of each parameter. */ - struct ipa_jump_func *jump_functions; -}; + struct ipa_jump_func GTY ((length ("%h.argument_count"))) *jump_functions; +} ipa_edge_args_t; /* ipa_edge_args access functions. Please use these to access fields that are or will be shared among various passes. */ @@ -321,18 +319,17 @@ ipa_get_ith_jump_func (struct ipa_edge_args *args, int i) /* Vectors need to have typedefs of structures. */ typedef struct ipa_node_params ipa_node_params_t; -typedef struct ipa_edge_args ipa_edge_args_t; /* Types of vectors holding the infos. */ DEF_VEC_O (ipa_node_params_t); DEF_VEC_ALLOC_O (ipa_node_params_t, heap); DEF_VEC_O (ipa_edge_args_t); -DEF_VEC_ALLOC_O (ipa_edge_args_t, heap); +DEF_VEC_ALLOC_O (ipa_edge_args_t, gc); /* Vector where the parameter infos are actually stored. */ extern VEC (ipa_node_params_t, heap) *ipa_node_params_vector; /* Vector where the parameter infos are actually stored. */ -extern VEC (ipa_edge_args_t, heap) *ipa_edge_args_vector; +extern GTY(()) VEC (ipa_edge_args_t, gc) *ipa_edge_args_vector; /* Return the associated parameter/argument info corresponding to the given node/edge. */ @@ -378,12 +375,12 @@ static inline void ipa_check_create_edge_args (void) { if (!ipa_edge_args_vector) - ipa_edge_args_vector = VEC_alloc (ipa_edge_args_t, heap, + ipa_edge_args_vector = VEC_alloc (ipa_edge_args_t, gc, cgraph_edge_max_uid); if (VEC_length (ipa_edge_args_t, ipa_edge_args_vector) <= (unsigned) cgraph_edge_max_uid) - VEC_safe_grow_cleared (ipa_edge_args_t, heap, ipa_edge_args_vector, + VEC_safe_grow_cleared (ipa_edge_args_t, gc, ipa_edge_args_vector, cgraph_edge_max_uid + 1); } @@ -508,6 +505,10 @@ ipa_parm_adjustment_vec ipa_combine_adjustments (ipa_parm_adjustment_vec, ipa_parm_adjustment_vec); void ipa_dump_param_adjustments (FILE *, ipa_parm_adjustment_vec, tree); +void ipa_prop_write_jump_functions (cgraph_node_set set); +void ipa_prop_read_jump_functions (void); +void ipa_update_after_lto_read (void); + /* From tree-sra.c: */ bool build_ref_for_offset (tree *, tree, HOST_WIDE_INT, tree, bool); diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 04d4e112ed3..e37af05d08e 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see #include "diagnostic.h" #include "langhooks.h" #include "target.h" +#include "lto-streamer.h" #include "cfgloop.h" #include "tree-scalar-evolution.h" @@ -329,12 +330,11 @@ check_call (funct_state local, gimple call, bool ipa) /* When not in IPA mode, we can still handle self recursion. */ if (!ipa && callee_t == current_function_decl) local->looping = true; - /* The callee is either unknown (indirect call) or there is just no - scannable code for it (external call) . We look to see if there - are any bits available for the callee (such as by declaration or - because it is builtin) and process solely on the basis of those - bits. */ - else if (avail <= AVAIL_OVERWRITABLE || !ipa) + /* Either calle is unknown or we are doing local analysis. + Look to see if there are any bits available for the callee (such as by + declaration or because it is builtin) and process solely on the basis of + those bits. */ + else if (!ipa || !callee_t) { if (possibly_throws && flag_non_call_exceptions) { @@ -491,13 +491,6 @@ analyze_function (struct cgraph_node *fn, bool ipa) funct_state l; basic_block this_block; - if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE) - { - if (dump_file) - fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n"); - return NULL; - } - l = XCNEW (struct funct_state_d); l->pure_const_state = IPA_CONST; l->state_previously_known = IPA_NEITHER; @@ -608,7 +601,7 @@ end: static void add_new_function (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) { - if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) + if (cgraph_function_body_availability (node) < AVAIL_OVERWRITABLE) return; /* There are some shared nodes, in particular the initializers on static declarations. We do not need to scan them more than once @@ -648,13 +641,15 @@ remove_node_data (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) } -/* Analyze each function in the cgraph to see if it is locally PURE or - CONST. */ - -static void -generate_summary (void) +static void +register_hooks (void) { - struct cgraph_node *node; + static bool init_p = false; + + if (init_p) + return; + + init_p = true; node_removal_hook_holder = cgraph_add_node_removal_hook (&remove_node_data, NULL); @@ -662,6 +657,19 @@ generate_summary (void) cgraph_add_node_duplication_hook (&duplicate_node_data, NULL); function_insertion_hook_holder = cgraph_add_function_insertion_hook (&add_new_function, NULL); +} + + +/* Analyze each function in the cgraph to see if it is locally PURE or + CONST. */ + +static void +generate_summary (void) +{ + struct cgraph_node *node; + + register_hooks (); + /* There are some shared nodes, in particular the initializers on static declarations. We do not need to scan them more than once since all we would be interested in are the addressof @@ -670,18 +678,132 @@ generate_summary (void) /* Process all of the functions. - We do NOT process any AVAIL_OVERWRITABLE functions, we cannot - guarantee that what we learn about the one we see will be true - for the one that overrides it. - */ + We process AVAIL_OVERWRITABLE functions. We can not use the results + by default, but the info can be used at LTO with -fwhole-program or + when function got clonned and the clone is AVAILABLE. */ + for (node = cgraph_nodes; node; node = node->next) - if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE) + if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) set_function_state (node, analyze_function (node, true)); pointer_set_destroy (visited_nodes); visited_nodes = NULL; } + +/* Serialize the ipa info for lto. */ + +static void +pure_const_write_summary (cgraph_node_set set) +{ + struct cgraph_node *node; + struct lto_simple_output_block *ob + = lto_create_simple_output_block (LTO_section_ipa_pure_const); + unsigned int count = 0; + cgraph_node_set_iterator csi; + + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (node->analyzed && get_function_state (node) != NULL) + count++; + } + + lto_output_uleb128_stream (ob->main_stream, count); + + /* Process all of the functions. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (node->analyzed && get_function_state (node) != NULL) + { + struct bitpack_d *bp; + funct_state fs; + int node_ref; + lto_cgraph_encoder_t encoder; + + fs = get_function_state (node); + + encoder = ob->decl_state->cgraph_node_encoder; + node_ref = lto_cgraph_encoder_encode (encoder, node); + lto_output_uleb128_stream (ob->main_stream, node_ref); + + /* Note that flags will need to be read in the opposite + order as we are pushing the bitflags into FLAGS. */ + bp = bitpack_create (); + bp_pack_value (bp, fs->pure_const_state, 2); + bp_pack_value (bp, fs->state_previously_known, 2); + bp_pack_value (bp, fs->looping_previously_known, 1); + bp_pack_value (bp, fs->looping, 1); + bp_pack_value (bp, fs->can_throw, 1); + lto_output_bitpack (ob->main_stream, bp); + bitpack_delete (bp); + } + } + + lto_destroy_simple_output_block (ob); +} + + +/* Deserialize the ipa info for lto. */ + +static void +pure_const_read_summary (void) +{ + struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); + struct lto_file_decl_data *file_data; + unsigned int j = 0; + + register_hooks (); + while ((file_data = file_data_vec[j++])) + { + const char *data; + size_t len; + struct lto_input_block *ib + = lto_create_simple_input_block (file_data, + LTO_section_ipa_pure_const, + &data, &len); + if (ib) + { + unsigned int i; + unsigned int count = lto_input_uleb128 (ib); + + for (i = 0; i < count; i++) + { + unsigned int index; + struct cgraph_node *node; + struct bitpack_d *bp; + funct_state fs; + lto_cgraph_encoder_t encoder; + + fs = XCNEW (struct funct_state_d); + index = lto_input_uleb128 (ib); + encoder = file_data->cgraph_node_encoder; + node = lto_cgraph_encoder_deref (encoder, index); + set_function_state (node, fs); + + /* Note that the flags must be read in the opposite + order in which they were written (the bitflags were + pushed into FLAGS). */ + bp = lto_input_bitpack (ib); + fs->pure_const_state + = (enum pure_const_state_e) bp_unpack_value (bp, 2); + fs->state_previously_known + = (enum pure_const_state_e) bp_unpack_value (bp, 2); + fs->looping_previously_known = bp_unpack_value (bp, 1); + fs->looping = bp_unpack_value (bp, 1); + fs->can_throw = bp_unpack_value (bp, 1); + bitpack_delete (bp); + } + + lto_destroy_simple_input_block (file_data, + LTO_section_ipa_pure_const, + ib, data, len); + } + } +} + + static bool ignore_edge (struct cgraph_edge *e) { @@ -748,6 +870,12 @@ propagate (void) if (w_l->looping) looping = true; + if (cgraph_function_body_availability (w) == AVAIL_OVERWRITABLE) + { + looping |= w_l->looping_previously_known; + if (pure_const_state < w_l->state_previously_known) + pure_const_state = w_l->state_previously_known; + } if (pure_const_state == IPA_NEITHER) break; @@ -771,6 +899,20 @@ propagate (void) if (y_l->looping) looping = true; } + else + { + int flags = flags_from_decl_or_type (y->decl); + + if (flags & ECF_LOOPING_CONST_OR_PURE) + looping = true; + if (flags & ECF_CONST) + ; + else if ((flags & ECF_PURE) && pure_const_state == IPA_CONST) + pure_const_state = IPA_PURE; + else + pure_const_state = IPA_NEITHER, looping = true; + + } } w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; @@ -858,7 +1000,8 @@ propagate (void) struct cgraph_edge *e; funct_state w_l = get_function_state (w); - if (w_l->can_throw) + if (w_l->can_throw + || cgraph_function_body_availability (w) == AVAIL_OVERWRITABLE) can_throw = true; if (can_throw) @@ -878,6 +1021,8 @@ propagate (void) && e->can_throw_external) can_throw = true; } + else if (e->can_throw_external && !TREE_NOTHROW (y->decl)) + can_throw = true; } w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; @@ -916,7 +1061,7 @@ propagate (void) free (node->aux); node->aux = NULL; } - if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE) + if (cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE) free (get_function_state (node)); } @@ -952,8 +1097,8 @@ struct ipa_opt_pass_d pass_ipa_pure_const = 0 /* todo_flags_finish */ }, generate_summary, /* generate_summary */ - NULL, /* write_summary */ - NULL, /* read_summary */ + pure_const_write_summary, /* write_summary */ + pure_const_read_summary, /* read_summary */ NULL, /* function_read_summary */ 0, /* TODOs */ NULL, /* function_transform */ @@ -979,15 +1124,16 @@ local_pure_const (void) fprintf (dump_file, "Function called in recursive cycle; ignoring\n"); return 0; } - - l = analyze_function (cgraph_node (current_function_decl), false); - if (!l) + if (cgraph_function_body_availability (cgraph_node (current_function_decl)) + <= AVAIL_OVERWRITABLE) { if (dump_file) fprintf (dump_file, "Function has wrong visibility; ignoring\n"); return 0; } + l = analyze_function (cgraph_node (current_function_decl), false); + switch (l->pure_const_state) { case IPA_CONST: diff --git a/gcc/ipa-reference.c b/gcc/ipa-reference.c index 10daf56eab6..8610f13311f 100644 --- a/gcc/ipa-reference.c +++ b/gcc/ipa-reference.c @@ -68,6 +68,15 @@ along with GCC; see the file COPYING3. If not see #include "timevar.h" #include "diagnostic.h" #include "langhooks.h" +#include "lto-streamer.h" + +static void add_new_function (struct cgraph_node *node, + void *data ATTRIBUTE_UNUSED); +static void remove_node_data (struct cgraph_node *node, + void *data ATTRIBUTE_UNUSED); +static void duplicate_node_data (struct cgraph_node *src, + struct cgraph_node *dst, + void *data ATTRIBUTE_UNUSED); /* The static variables defined within the compilation unit that are loaded or stored directly by function that owns this structure. */ @@ -309,6 +318,8 @@ has_proper_scope_for_analysis (tree t) if (!TREE_STATIC (t) && !DECL_EXTERNAL (t)) return false; + /* FIXME: for LTO we should include PUBLIC vars too. This is bit difficult + as summarie would need unsharing. */ if (DECL_EXTERNAL (t) || TREE_PUBLIC (t)) return false; @@ -404,31 +415,25 @@ check_call (ipa_reference_local_vars_info_t local, gimple stmt) { int flags = gimple_call_flags (stmt); tree callee_t = gimple_call_fndecl (stmt); - enum availability avail = AVAIL_NOT_AVAILABLE; - if (callee_t) + /* Process indirect calls. All direct calles are handled at propagation + time. */ + if (!callee_t) { - struct cgraph_node* callee = cgraph_node(callee_t); - avail = cgraph_function_body_availability (callee); - } - - if (avail <= AVAIL_OVERWRITABLE) - if (local) - { - if (flags & ECF_CONST) - ; - else if (flags & ECF_PURE) + if (flags & ECF_CONST) + ; + else if (flags & ECF_PURE) + local->calls_read_all = true; + else + { local->calls_read_all = true; - else - { - local->calls_read_all = true; + /* When function does not reutrn, it is safe to ignore anythign it writes + to, because the effect will never happen. */ + if ((flags & (ECF_NOTHROW | ECF_NORETURN)) + != (ECF_NOTHROW | ECF_NORETURN)) local->calls_write_all = true; - } - } - /* TODO: To be able to produce sane results, we should also handle - common builtins, in particular throw. - Indirect calls hsould be only counted and as inliner is replacing them - by direct calls, we can conclude if any indirect calls are left in body */ + } + } } /* TP is the part of the tree currently under the microscope. @@ -518,7 +523,7 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x { struct cgraph_node *y = e->callee; - /* Only look at the master nodes and skip external nodes. */ + /* Only look into nodes we can propagate something. */ if (cgraph_function_body_availability (e->callee) > AVAIL_OVERWRITABLE) { if (get_reference_vars_info (y)) @@ -578,6 +583,13 @@ propagate_bits (ipa_reference_global_vars_info_t x_global, struct cgraph_node *x static void ipa_init (void) { + static bool init_p = false; + + if (init_p) + return; + + init_p = true; + memory_identifier_string = build_string(7, "memory"); reference_vars_to_consider = @@ -594,6 +606,13 @@ ipa_init (void) since all we would be interested in are the addressof operations. */ visited_nodes = pointer_set_create (); + + function_insertion_hook_holder = + cgraph_add_function_insertion_hook (&add_new_function, NULL); + node_removal_hook_holder = + cgraph_add_node_removal_hook (&remove_node_data, NULL); + node_duplication_hook_holder = + cgraph_add_node_duplication_hook (&duplicate_node_data, NULL); } /* Check out the rhs of a static or global initialization VNODE to see @@ -614,6 +633,7 @@ analyze_variable (struct varpool_node *vnode) &wi, wi.pset); } + /* Set up the persistent info for FN. */ static ipa_reference_local_vars_info_t @@ -634,9 +654,10 @@ init_function_info (struct cgraph_node *fn) return l; } + /* This is the main routine for finding the reference patterns for global variables within a function FN. */ - + static void analyze_function (struct cgraph_node *fn) { @@ -646,6 +667,7 @@ analyze_function (struct cgraph_node *fn) #ifdef ENABLE_CHECKING tree step; #endif + ipa_reference_local_vars_info_t local; if (dump_file) fprintf (dump_file, "\n local analysis of %s\n", cgraph_node_name (fn)); @@ -680,6 +702,21 @@ analyze_function (struct cgraph_node *fn) scan_stmt_for_static_refs (&gsi, fn); } + local = get_reference_vars_info (fn)->local; + if ((flags_from_decl_or_type (decl) & (ECF_NOTHROW | ECF_NORETURN)) + == (ECF_NOTHROW | ECF_NORETURN)) + { + local->calls_write_all = false; + bitmap_clear (local->statics_written); + } + + /* Free bitmaps of direct references if we can not use them anyway. */ + if (local->calls_write_all) + BITMAP_FREE (local->statics_written); + if (local->calls_read_all) + BITMAP_FREE (local->statics_read); + + #ifdef ENABLE_CHECKING /* Verify that all local initializers was expanded by gimplifier. */ for (step = DECL_STRUCT_FUNCTION (decl)->local_decls; @@ -845,12 +882,6 @@ generate_summary (void) bitmap module_statics_readonly; bitmap bm_temp; - function_insertion_hook_holder = - cgraph_add_function_insertion_hook (&add_new_function, NULL); - node_removal_hook_holder = - cgraph_add_node_removal_hook (&remove_node_data, NULL); - node_duplication_hook_holder = - cgraph_add_node_duplication_hook (&duplicate_node_data, NULL); ipa_init (); module_statics_readonly = BITMAP_ALLOC (&local_info_obstack); bm_temp = BITMAP_ALLOC (&local_info_obstack); @@ -945,10 +976,12 @@ generate_summary (void) removed from the local maps. This will include all of the variables that were found to escape in the function scanning. */ - bitmap_and_into (l->statics_read, - all_module_statics); - bitmap_and_into (l->statics_written, - all_module_statics); + if (l->statics_read) + bitmap_and_into (l->statics_read, + all_module_statics); + if (l->statics_written) + bitmap_and_into (l->statics_written, + all_module_statics); } BITMAP_FREE(module_statics_readonly); @@ -967,26 +1000,203 @@ generate_summary (void) "\nFunction name:%s/%i:", cgraph_node_name (node), node->uid); fprintf (dump_file, "\n locals read: "); - EXECUTE_IF_SET_IN_BITMAP (l->statics_read, - 0, index, bi) - { - fprintf (dump_file, "%s ", - get_static_name (index)); - } + if (l->statics_read) + EXECUTE_IF_SET_IN_BITMAP (l->statics_read, + 0, index, bi) + { + fprintf (dump_file, "%s ", + get_static_name (index)); + } fprintf (dump_file, "\n locals written: "); - EXECUTE_IF_SET_IN_BITMAP (l->statics_written, - 0, index, bi) - { - fprintf(dump_file, "%s ", - get_static_name (index)); - } + if (l->statics_written) + EXECUTE_IF_SET_IN_BITMAP (l->statics_written, + 0, index, bi) + { + fprintf(dump_file, "%s ", + get_static_name (index)); + } if (l->calls_read_all) fprintf (dump_file, "\n calls read all: "); if (l->calls_write_all) fprintf (dump_file, "\n calls read all: "); } } + + +/* Return true if we need to write summary of NODE. */ + +static bool +write_node_summary_p (struct cgraph_node *node) +{ + gcc_assert (node->global.inlined_to == NULL); + return (node->analyzed + && cgraph_function_body_availability (node) >= AVAIL_OVERWRITABLE + && get_reference_vars_info (node) != NULL); +} + +/* Serialize the ipa info for lto. */ + +static void +ipa_reference_write_summary (cgraph_node_set set) +{ + struct cgraph_node *node; + struct lto_simple_output_block *ob + = lto_create_simple_output_block (LTO_section_ipa_reference); + unsigned int count = 0; + cgraph_node_set_iterator csi; + + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + if (write_node_summary_p (csi_node (csi))) + count++; + + lto_output_uleb128_stream (ob->main_stream, count); + + /* Process all of the functions. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (write_node_summary_p (node)) + { + ipa_reference_local_vars_info_t l + = get_reference_vars_info (node)->local; + unsigned int index; + bitmap_iterator bi; + lto_cgraph_encoder_t encoder; + int node_ref; + + encoder = ob->decl_state->cgraph_node_encoder; + node_ref = lto_cgraph_encoder_encode (encoder, node); + lto_output_uleb128_stream (ob->main_stream, node_ref); + + /* Stream out the statics read. */ + if (l->calls_read_all) + lto_output_sleb128_stream (ob->main_stream, -1); + else + { + lto_output_sleb128_stream (ob->main_stream, + bitmap_count_bits (l->statics_read)); + EXECUTE_IF_SET_IN_BITMAP (l->statics_read, 0, index, bi) + lto_output_var_decl_index(ob->decl_state, ob->main_stream, + get_static_decl (index)); + } + + /* Stream out the statics written. */ + if (l->calls_write_all) + lto_output_sleb128_stream (ob->main_stream, -1); + else + { + lto_output_sleb128_stream (ob->main_stream, + bitmap_count_bits (l->statics_written)); + EXECUTE_IF_SET_IN_BITMAP (l->statics_written, 0, index, bi) + lto_output_var_decl_index(ob->decl_state, ob->main_stream, + get_static_decl (index)); + } + } + } + lto_destroy_simple_output_block (ob); +} + + +/* Deserialize the ipa info for lto. */ + +static void +ipa_reference_read_summary (void) +{ + struct lto_file_decl_data ** file_data_vec + = lto_get_file_decl_data (); + struct lto_file_decl_data * file_data; + unsigned int j = 0; + + ipa_init (); + + while ((file_data = file_data_vec[j++])) + { + const char *data; + size_t len; + struct lto_input_block *ib + = lto_create_simple_input_block (file_data, + LTO_section_ipa_reference, + &data, &len); + if (ib) + { + unsigned int i; + unsigned int f_count = lto_input_uleb128 (ib); + + for (i = 0; i < f_count; i++) + { + unsigned int j, index; + struct cgraph_node *node; + ipa_reference_local_vars_info_t l; + int v_count; + lto_cgraph_encoder_t encoder; + + index = lto_input_uleb128 (ib); + encoder = file_data->cgraph_node_encoder; + node = lto_cgraph_encoder_deref (encoder, index); + l = init_function_info (node); + + /* Set the statics read. */ + v_count = lto_input_sleb128 (ib); + if (v_count == -1) + l->calls_read_all = true; + else + for (j = 0; j < (unsigned int)v_count; j++) + { + unsigned int var_index = lto_input_uleb128 (ib); + tree v_decl = lto_file_decl_data_get_var_decl (file_data, + var_index); + add_static_var (v_decl); + bitmap_set_bit (l->statics_read, DECL_UID (v_decl)); + } + + /* Set the statics written. */ + v_count = lto_input_sleb128 (ib); + if (v_count == -1) + l->calls_write_all = true; + else + for (j = 0; j < (unsigned int)v_count; j++) + { + unsigned int var_index = lto_input_uleb128 (ib); + tree v_decl = lto_file_decl_data_get_var_decl (file_data, + var_index); + add_static_var (v_decl); + bitmap_set_bit (l->statics_written, DECL_UID (v_decl)); + } + } + + lto_destroy_simple_input_block (file_data, + LTO_section_ipa_reference, + ib, data, len); + } + } +} + + +/* Set READ_ALL/WRITE_ALL based on DECL flags. */ +static void +read_write_all_from_decl (tree decl, bool * read_all, bool * write_all) +{ + int flags = flags_from_decl_or_type (decl); + if (flags & ECF_CONST) + ; + else if (flags & ECF_PURE) + *read_all = true; + else + { + /* TODO: To be able to produce sane results, we should also handle + common builtins, in particular throw. + Indirect calls hsould be only counted and as inliner is replacing them + by direct calls, we can conclude if any indirect calls are left in body */ + *read_all = true; + /* When function does not reutrn, it is safe to ignore anythign it writes + to, because the effect will never happen. */ + if ((flags & (ECF_NOTHROW | ECF_NORETURN)) + != (ECF_NOTHROW | ECF_NORETURN)) + *write_all = true; + } +} + /* Produce the global information by preforming a transitive closure on the local information that was produced by ipa_analyze_function and ipa_analyze_variable. */ @@ -1019,6 +1229,7 @@ propagate (void) ipa_reference_global_vars_info_t node_g = XCNEW (struct ipa_reference_global_vars_info_d); ipa_reference_local_vars_info_t node_l; + struct cgraph_edge *e; bool read_all; bool write_all; @@ -1039,6 +1250,15 @@ propagate (void) read_all = node_l->calls_read_all; write_all = node_l->calls_write_all; + /* When function is overwrittable, we can not assume anything. */ + if (cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (node->decl, &read_all, &write_all); + + for (e = node->callees; e; e = e->next_callee) + if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (e->callee->decl, &read_all, &write_all); + + /* If any node in a cycle is calls_read_all or calls_write_all they all are. */ w_info = (struct ipa_dfs_info *) node->aux; @@ -1047,6 +1267,15 @@ propagate (void) { ipa_reference_local_vars_info_t w_l = get_reference_vars_info (w)->local; + + /* When function is overwrittable, we can not assume anything. */ + if (cgraph_function_body_availability (w) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (w->decl, &read_all, &write_all); + + for (e = w->callees; e; e = e->next_callee) + if (cgraph_function_body_availability (e->callee) <= AVAIL_OVERWRITABLE) + read_write_all_from_decl (e->callee->decl, &read_all, &write_all); + read_all |= w_l->calls_read_all; write_all |= w_l->calls_write_all; @@ -1054,6 +1283,7 @@ propagate (void) w = w_info->next_cycle; } + /* Initialized the bitmaps for the reduced nodes */ if (read_all) node_g->statics_read = all_module_statics; @@ -1063,7 +1293,6 @@ propagate (void) bitmap_copy (node_g->statics_read, node_l->statics_read); } - if (write_all) node_g->statics_written = all_module_statics; else @@ -1135,19 +1364,21 @@ propagate (void) "\nFunction name:%s/%i:", cgraph_node_name (node), node->uid); fprintf (dump_file, "\n locals read: "); - EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read, - 0, index, bi) - { - fprintf (dump_file, "%s ", - get_static_name (index)); - } + if (node_l->statics_read) + EXECUTE_IF_SET_IN_BITMAP (node_l->statics_read, + 0, index, bi) + { + fprintf (dump_file, "%s ", + get_static_name (index)); + } fprintf (dump_file, "\n locals written: "); - EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written, - 0, index, bi) - { - fprintf(dump_file, "%s ", - get_static_name (index)); - } + if (node_l->statics_written) + EXECUTE_IF_SET_IN_BITMAP (node_l->statics_written, + 0, index, bi) + { + fprintf(dump_file, "%s ", + get_static_name (index)); + } w_info = (struct ipa_dfs_info *) node->aux; w = w_info->next_cycle; @@ -1179,19 +1410,25 @@ propagate (void) w = w_info->next_cycle; } fprintf (dump_file, "\n globals read: "); - EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read, - 0, index, bi) - { - fprintf (dump_file, "%s ", - get_static_name (index)); - } + if (node_g->statics_read == all_module_statics) + fprintf (dump_file, "ALL"); + else + EXECUTE_IF_SET_IN_BITMAP (node_g->statics_read, + 0, index, bi) + { + fprintf (dump_file, "%s ", + get_static_name (index)); + } fprintf (dump_file, "\n globals written: "); - EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written, - 0, index, bi) - { - fprintf (dump_file, "%s ", - get_static_name (index)); - } + if (node_g->statics_written == all_module_statics) + fprintf (dump_file, "ALL"); + else + EXECUTE_IF_SET_IN_BITMAP (node_g->statics_written, + 0, index, bi) + { + fprintf (dump_file, "%s ", + get_static_name (index)); + } } } @@ -1271,8 +1508,8 @@ struct ipa_opt_pass_d pass_ipa_reference = 0 /* todo_flags_finish */ }, generate_summary, /* generate_summary */ - NULL, /* write_summary */ - NULL, /* read_summary */ + ipa_reference_write_summary, /* write_summary */ + ipa_reference_read_summary, /* read_summary */ NULL, /* function_read_summary */ 0, /* TODOs */ NULL, /* function_transform */ diff --git a/gcc/ipa-struct-reorg.c b/gcc/ipa-struct-reorg.c index bc84eee372b..147610a43e4 100644 --- a/gcc/ipa-struct-reorg.c +++ b/gcc/ipa-struct-reorg.c @@ -258,15 +258,21 @@ find_field_in_struct_1 (tree str_type, tree field) { tree str_field; + if (!DECL_NAME (field)) + return NULL; + for (str_field = TYPE_FIELDS (str_type); str_field; str_field = TREE_CHAIN (str_field)) { - const char * str_field_name; - const char * field_name; + const char *str_field_name; + const char *field_name; + + if (!DECL_NAME (str_field)) + continue; str_field_name = IDENTIFIER_POINTER (DECL_NAME (str_field)); field_name = IDENTIFIER_POINTER (DECL_NAME (field)); - + gcc_assert (str_field_name); gcc_assert (field_name); @@ -274,7 +280,7 @@ find_field_in_struct_1 (tree str_type, tree field) { /* Check field types. */ if (is_equal_types (TREE_TYPE (str_field), TREE_TYPE (field))) - return str_field; + return str_field; } } @@ -3374,6 +3380,14 @@ build_data_structure (VEC (tree, heap) **unsuitable_types) if (is_candidate (var, &type, unsuitable_types)) add_structure (type); + if (fn == NULL) + { + /* Skip cones that haven't been materialized yet. */ + gcc_assert (c_node->clone_of + && c_node->clone_of->decl != c_node->decl); + continue; + } + /* Check function local variables. */ for (var_list = fn->local_decls; var_list; var_list = TREE_CHAIN (var_list)) diff --git a/gcc/ipa.c b/gcc/ipa.c index 9204caae77b..c859242fa70 100644 --- a/gcc/ipa.c +++ b/gcc/ipa.c @@ -52,7 +52,9 @@ cgraph_postorder (struct cgraph_node **order) for (pass = 0; pass < 2; pass++) for (node = cgraph_nodes; node; node = node->next) if (!node->aux - && (pass || (node->needed && !node->address_taken))) + && (pass + || (!cgraph_only_called_directly_p (node) + && !node->address_taken))) { node2 = node; if (!node->callers) @@ -132,11 +134,12 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) gcc_assert (!node->aux); #endif for (node = cgraph_nodes; node; node = node->next) - if (node->needed && !node->global.inlined_to + if (!cgraph_can_remove_if_no_direct_calls_p (node) && ((!DECL_EXTERNAL (node->decl)) || !node->analyzed || before_inlining_p)) { + gcc_assert (!node->global.inlined_to); node->aux = first; first = node; } @@ -248,6 +251,28 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) return changed; } +static bool +cgraph_externally_visible_p (struct cgraph_node *node, bool whole_program) +{ + if (!node->local.finalized) + return false; + if (!DECL_COMDAT (node->decl) + && (!TREE_PUBLIC (node->decl) || DECL_EXTERNAL (node->decl))) + return false; + if (!whole_program) + return true; + /* COMDAT functions must be shared only if they have address taken, + otherwise we can produce our own private implementation with + -fwhole-program. */ + if (DECL_COMDAT (node->decl) && (node->address_taken || !node->analyzed)) + return true; + if (MAIN_NAME_P (DECL_NAME (node->decl))) + return true; + if (lookup_attribute ("externally_visible", DECL_ATTRIBUTES (node->decl))) + return true; + return false; +} + /* Mark visibility of all functions. A local function is one whose calls can occur only in the current @@ -260,38 +285,48 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file) via visibilities for the backend point of view. */ static unsigned int -function_and_variable_visibility (void) +function_and_variable_visibility (bool whole_program) { struct cgraph_node *node; struct varpool_node *vnode; for (node = cgraph_nodes; node; node = node->next) { - if (node->reachable - && (DECL_COMDAT (node->decl) - || (!flag_whole_program - && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl)))) - node->local.externally_visible = true; + if (cgraph_externally_visible_p (node, whole_program)) + { + gcc_assert (!node->global.inlined_to); + node->local.externally_visible = true; + } + else + node->local.externally_visible = false; if (!node->local.externally_visible && node->analyzed && !DECL_EXTERNAL (node->decl)) { - gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl)); + gcc_assert (whole_program || !TREE_PUBLIC (node->decl)); TREE_PUBLIC (node->decl) = 0; + DECL_COMDAT (node->decl) = 0; + DECL_WEAK (node->decl) = 0; } - node->local.local = (!node->needed + node->local.local = (cgraph_only_called_directly_p (node) && node->analyzed && !DECL_EXTERNAL (node->decl) && !node->local.externally_visible); } for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) { + if (!vnode->finalized) + continue; if (vnode->needed - && !flag_whole_program - && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl))) - vnode->externally_visible = 1; + && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)) + && (!whole_program + || lookup_attribute ("externally_visible", + DECL_ATTRIBUTES (vnode->decl)))) + vnode->externally_visible = true; + else + vnode->externally_visible = false; if (!vnode->externally_visible) { - gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl)); + gcc_assert (whole_program || !TREE_PUBLIC (vnode->decl)); TREE_PUBLIC (vnode->decl) = 0; } gcc_assert (TREE_STATIC (vnode->decl)); @@ -314,13 +349,22 @@ function_and_variable_visibility (void) return 0; } +/* Local function pass handling visibilities. This happens before LTO streaming + so in particular -fwhole-program should be ignored at this level. */ + +static unsigned int +local_function_and_variable_visibility (void) +{ + return function_and_variable_visibility (flag_whole_program && !flag_lto && !flag_whopr); +} + struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility = { { SIMPLE_IPA_PASS, "visibility", /* name */ NULL, /* gate */ - function_and_variable_visibility, /* execute */ + local_function_and_variable_visibility,/* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */ @@ -333,6 +377,58 @@ struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility = } }; +/* Do not re-run on ltrans stage. */ + +static bool +gate_whole_program_function_and_variable_visibility (void) +{ + return !flag_ltrans; +} + +/* Bring functionss local at LTO time whith -fwhole-program. */ + +static unsigned int +whole_program_function_and_variable_visibility (void) +{ + struct cgraph_node *node; + struct varpool_node *vnode; + + function_and_variable_visibility (flag_whole_program); + + for (node = cgraph_nodes; node; node = node->next) + if (node->local.externally_visible && node->local.finalized) + cgraph_mark_needed_node (node); + for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed) + if (vnode->externally_visible) + varpool_mark_needed_node (vnode); + return 0; +} + +struct ipa_opt_pass_d pass_ipa_whole_program_visibility = +{ + { + IPA_PASS, + "whole-program", /* name */ + gate_whole_program_function_and_variable_visibility,/* gate */ + whole_program_function_and_variable_visibility,/* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_CGRAPHOPT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_cgraph | TODO_remove_functions/* todo_flags_finish */ + }, + NULL, /* generate_summary */ + NULL, /* write_summary */ + NULL, /* read_summary */ + NULL, /* function_read_summary */ + 0, /* TODOs */ + NULL, /* function_transform */ + NULL, /* variable_transform */ +}; /* Hash a cgraph node set element. */ diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c index fd756f6de73..4b9d29f1db1 100644 --- a/gcc/ira-costs.c +++ b/gcc/ira-costs.c @@ -1665,6 +1665,7 @@ ira_finish_costs_once (void) static void init_costs (void) { + init_subregs_of_mode (); costs = (struct costs *) ira_allocate (max_struct_costs_size * cost_elements_num); pref_buffer diff --git a/gcc/ira-lives.c b/gcc/ira-lives.c index 57a953bad59..c67e89cbd79 100644 --- a/gcc/ira-lives.c +++ b/gcc/ira-lives.c @@ -500,7 +500,7 @@ check_and_make_def_conflict (int alt, int def, enum reg_class def_cl) for (use = 0; use < recog_data.n_operands; use++) { if (use == def || recog_data.operand_type[use] == OP_OUT) - return; + continue; if (recog_op_alt[use][alt].anything_ok) use_cl = ALL_REGS; @@ -513,7 +513,7 @@ check_and_make_def_conflict (int alt, int def, enum reg_class def_cl) if ((use_match = recog_op_alt[use][alt].matches) >= 0) { if (use_match == def) - return; + continue; if (recog_op_alt[use_match][alt].anything_ok) use_cl = ALL_REGS; @@ -841,6 +841,7 @@ process_single_reg_class_operands (bool in_p, int freq) [ira_class_hard_regs[cl][0]]) >= 0 && reg_class_size[cl] <= (unsigned) CLASS_MAX_NREGS (cl, mode)) { + int i, size; cost = (freq * (in_p @@ -848,10 +849,12 @@ process_single_reg_class_operands (bool in_p, int freq) : ira_get_register_move_cost (mode, cl, cover_class))); ira_allocate_and_set_costs (&ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a), cover_class, 0); - ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a) - [ira_class_hard_reg_index - [cover_class][ira_class_hard_regs[cl][0]]] - -= cost; + size = ira_reg_class_nregs[cover_class][mode]; + for (i = 0; i < size; i++) + ALLOCNO_CONFLICT_HARD_REG_COSTS (operand_a) + [ira_class_hard_reg_index + [cover_class][ira_class_hard_regs[cl][i]]] + -= cost; } } diff --git a/gcc/ira.c b/gcc/ira.c index b960f769534..a3e899f8313 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -1442,6 +1442,9 @@ ira_setup_eliminable_regset (void) int need_fp = (! flag_omit_frame_pointer || (cfun->calls_alloca && EXIT_IGNORE_STACK) + /* We need the frame pointer to catch stack overflow exceptions + if the stack pointer is moving. */ + || (flag_stack_check && STACK_CHECK_MOVING_SP) || crtl->accesses_prior_frames || crtl->stack_realign_needed || targetm.frame_pointer_required ()); @@ -3132,6 +3135,9 @@ ira (FILE *f) epilogue thus changing register elimination offsets. */ current_function_is_leaf = leaf_function_p (); + if (resize_reg_info () && flag_ira_loop_pressure) + ira_set_pseudo_classes (ira_dump_file); + rebuild_p = update_equiv_regs (); #ifndef IRA_NO_OBSTACK @@ -3158,7 +3164,6 @@ ira (FILE *f) } max_regno_before_ira = allocated_reg_info_size = max_reg_num (); - resize_reg_info (); ira_setup_eliminable_regset (); ira_overall_cost = ira_reg_cost = ira_mem_cost = 0; @@ -3272,6 +3277,8 @@ ira (FILE *f) reload_completed = !reload (get_insns (), ira_conflicts_p); + finish_subregs_of_mode (); + timevar_pop (TV_RELOAD); timevar_push (TV_IRA); diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 5a9f1d6e010..7815bc8a050 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,14 @@ +2009-10-20 Joel Dice + + PR java/28474 + * mangle_name.c (append_unicode_mangled_name): Fix mangling + of names with multiple underscores and "U". + (unicode_mangling_length): Likewise. + +2009-10-03 Simon Baldwin + + * config-lang.in (lang_dirs): Remove zlib. + 2009-09-28 Richard Henderson * builtins.c (initialize_builtins): Update call to diff --git a/gcc/java/config-lang.in b/gcc/java/config-lang.in index d3a4d4dbbe5..29ee3fd8547 100644 --- a/gcc/java/config-lang.in +++ b/gcc/java/config-lang.in @@ -35,6 +35,6 @@ compilers="jc1\$(exeext) jvgenmain\$(exeext)" gtfiles="\$(srcdir)/java/java-tree.h \$(srcdir)/java/jcf.h \$(srcdir)/java/parse.h \$(srcdir)/java/builtins.c \$(srcdir)/java/class.c \$(srcdir)/java/constants.c \$(srcdir)/java/decl.c \$(srcdir)/java/expr.c \$(srcdir)/java/jcf-parse.c \$(srcdir)/java/lang.c \$(srcdir)/java/mangle.c \$(srcdir)/java/resource.c" target_libs=${libgcj_saved} -lang_dirs="zlib fastjar" +lang_dirs="fastjar" #build_by_default=no lang_requires=c++ diff --git a/gcc/java/mangle_name.c b/gcc/java/mangle_name.c index a0e6887a04e..a75f5cad090 100644 --- a/gcc/java/mangle_name.c +++ b/gcc/java/mangle_name.c @@ -266,7 +266,10 @@ append_unicode_mangled_name (const char *name, int len) int ch = UTF8_GET(ptr, limit); if ((ISALNUM (ch) && ch != 'U') || ch == '$') - obstack_1grow (mangle_obstack, ch); + { + obstack_1grow (mangle_obstack, ch); + uuU = 0; + } /* Everything else needs encoding */ else { @@ -321,7 +324,10 @@ unicode_mangling_length (const char *name, int len) if (ch < 0) error ("internal error - invalid Utf8 name"); if ((ISALNUM (ch) && ch != 'U') || ch == '$') - num_chars++; + { + num_chars++; + uuU = 0; + } /* Everything else needs encoding */ else { diff --git a/gcc/jump.c b/gcc/jump.c index a12d0404500..6ebc7ef1cd7 100644 --- a/gcc/jump.c +++ b/gcc/jump.c @@ -1695,6 +1695,10 @@ rtx_renumbered_equal_p (const_rtx x, const_rtx y) if (GET_MODE (x) != GET_MODE (y)) return 0; + /* MEMs refering to different address space are not equivalent. */ + if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y)) + return 0; + /* For commutative operations, the RTX match if the operand match in any order. Also handle the simple binary and unary cases without a loop. */ if (targetm.commutative_p (x, UNKNOWN)) diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 40a4de93d6d..4f01483846b 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -62,7 +62,7 @@ extern bool lhd_decl_ok_for_sibcall (const_tree); extern size_t lhd_tree_size (enum tree_code); extern HOST_WIDE_INT lhd_to_target_charset (HOST_WIDE_INT); extern tree lhd_expr_to_decl (tree, bool *, bool *); -extern tree lhd_builtin_function (tree decl); +extern tree lhd_builtin_function (tree); /* Declarations of default tree inlining hooks. */ extern void lhd_initialize_diagnostics (struct diagnostic_context *); @@ -236,6 +236,21 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_OMP_FINISH_CLAUSE \ } +/* LTO hooks. */ +extern void lhd_begin_section (const char *); +extern void lhd_append_data (const void *, size_t, void *); +extern void lhd_end_section (void); + +#define LANG_HOOKS_BEGIN_SECTION lhd_begin_section +#define LANG_HOOKS_APPEND_DATA lhd_append_data +#define LANG_HOOKS_END_SECTION lhd_end_section + +#define LANG_HOOKS_LTO { \ + LANG_HOOKS_BEGIN_SECTION, \ + LANG_HOOKS_APPEND_DATA, \ + LANG_HOOKS_END_SECTION \ +} + /* The whole thing. The structure is defined in langhooks.h. */ #define LANG_HOOKS_INITIALIZER { \ LANG_HOOKS_NAME, \ @@ -273,6 +288,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_TREE_DUMP_INITIALIZER, \ LANG_HOOKS_DECLS, \ LANG_HOOKS_FOR_TYPES_INITIALIZER, \ + LANG_HOOKS_LTO, \ LANG_HOOKS_GET_INNERMOST_GENERIC_PARMS, \ LANG_HOOKS_GET_INNERMOST_GENERIC_ARGS, \ LANG_HOOKS_FUNCTION_PARAMETER_PACK_P, \ diff --git a/gcc/langhooks.c b/gcc/langhooks.c index 092a3238592..633caf58c53 100644 --- a/gcc/langhooks.c +++ b/gcc/langhooks.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "ggc.h" #include "diagnostic.h" #include "cgraph.h" +#include "output.h" /* Do nothing; in many cases the default hook. */ @@ -584,3 +585,54 @@ lhd_builtin_function (tree decl) lang_hooks.decls.pushdecl (decl); return decl; } + +/* LTO hooks. */ + +/* Used to save and restore any previously active section. */ +static section *saved_section; + + +/* Begin a new LTO output section named NAME. This default implementation + saves the old section and emits assembly code to switch to the new + section. */ + +void +lhd_begin_section (const char *name) +{ + section *section; + + /* Save the old section so we can restore it in lto_end_asm_section. */ + gcc_assert (!saved_section); + saved_section = in_section; + + /* Create a new section and switch to it. */ + section = get_section (name, SECTION_DEBUG, NULL); + switch_to_section (section); +} + + +/* Write DATA of length LEN to the current LTO output section. This default + implementation just calls assemble_string and frees BLOCK. */ + +void +lhd_append_data (const void *data, size_t len, void *block) +{ + if (data) + assemble_string ((const char *)data, len); + free (block); +} + + +/* Finish the current LTO output section. This default implementation emits + assembly code to switch to any section previously saved by + lhd_begin_section. */ + +void +lhd_end_section (void) +{ + if (saved_section) + { + switch_to_section (saved_section); + saved_section = NULL; + } +} diff --git a/gcc/langhooks.h b/gcc/langhooks.h index b133ea05763..81f24366234 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -231,6 +231,23 @@ struct lang_hooks_for_decls void (*omp_finish_clause) (tree clause); }; +/* Language hooks related to LTO serialization. */ + +struct lang_hooks_for_lto +{ + /* Begin a new LTO section named NAME. */ + void (*begin_section) (const char *name); + + /* Write DATA of length LEN to the currently open LTO section. BLOCK is a + pointer to the dynamically allocated memory containing DATA. The + append_data function is responsible for freeing it when it is no longer + needed. */ + void (*append_data) (const void *data, size_t len, void *block); + + /* End the previously begun LTO section. */ + void (*end_section) (void); +}; + /* Language-specific hooks. See langhooks-def.h for defaults. */ struct lang_hooks @@ -386,6 +403,8 @@ struct lang_hooks struct lang_hooks_for_types types; + struct lang_hooks_for_lto lto; + /* Returns the generic parameters of an instantiation of a generic type or decl, e.g. C++ template instantiation. */ tree (*get_innermost_generic_parms) (const_tree); diff --git a/gcc/loop-invariant.c b/gcc/loop-invariant.c index 11a8310f33e..37f88f2fcbd 100644 --- a/gcc/loop-invariant.c +++ b/gcc/loop-invariant.c @@ -39,9 +39,9 @@ along with GCC; see the file COPYING3. If not see #include "system.h" #include "coretypes.h" #include "tm.h" +#include "hard-reg-set.h" #include "rtl.h" #include "tm_p.h" -#include "hard-reg-set.h" #include "obstack.h" #include "basic-block.h" #include "cfgloop.h" @@ -54,6 +54,8 @@ along with GCC; see the file COPYING3. If not see #include "hashtab.h" #include "except.h" #include "params.h" +#include "regs.h" +#include "ira.h" /* The data stored for the loop. */ @@ -61,6 +63,12 @@ struct loop_data { struct loop *outermost_exit; /* The outermost exit of the loop. */ bool has_call; /* True if the loop contains a call. */ + /* Maximal register pressure inside loop for given register class + (defined only for the cover classes). */ + int max_reg_pressure[N_REG_CLASSES]; + /* Loop regs referenced and live pseudo-registers. */ + bitmap_head regs_ref; + bitmap_head regs_live; }; #define LOOP_DATA(LOOP) ((struct loop_data *) (LOOP)->aux) @@ -100,6 +108,10 @@ struct invariant value. */ rtx reg; + /* If we moved the invariant out of the loop, the original regno + that contained its value. */ + int orig_regno; + /* The definition of the invariant. */ struct def *def; @@ -126,6 +138,9 @@ struct invariant unsigned stamp; }; +/* Currently processed loop. */ +static struct loop *curr_loop; + /* Table of invariants indexed by the df_ref uid field. */ static unsigned int invariant_table_size = 0; @@ -615,7 +630,12 @@ find_exits (struct loop *loop, basic_block *body, } } - loop->aux = xcalloc (1, sizeof (struct loop_data)); + if (loop->aux == NULL) + { + loop->aux = xcalloc (1, sizeof (struct loop_data)); + bitmap_initialize (&LOOP_DATA (loop)->regs_ref, ®_obstack); + bitmap_initialize (&LOOP_DATA (loop)->regs_live, ®_obstack); + } LOOP_DATA (loop)->outermost_exit = outermost_exit; LOOP_DATA (loop)->has_call = has_call; } @@ -685,8 +705,17 @@ create_new_invariant (struct def *def, rtx insn, bitmap depends_on, if (def) { inv->cost = rtx_cost (set, SET, speed); + /* ??? Try to determine cheapness of address computation. Unfortunately + the address cost is only a relative measure, we can't really compare + it with any absolute number, but only with other address costs. + But here we don't have any other addresses, so compare with a magic + number anyway. It has to be large enough to not regress PR33928 + (by avoiding to move reg+8,reg+16,reg+24 invariants), but small + enough to not regress 410.bwaves either (by still moving reg+reg + invariants). + See http://gcc.gnu.org/ml/gcc-patches/2009-10/msg01210.html . */ inv->cheap_address = address_cost (SET_SRC (set), word_mode, - speed) < COSTS_N_INSNS (1); + ADDR_SPACE_GENERIC, speed) < 3; } else { @@ -696,6 +725,7 @@ create_new_invariant (struct def *def, rtx insn, bitmap depends_on, inv->move = false; inv->reg = NULL_RTX; + inv->orig_regno = -1; inv->stamp = 0; inv->insn = insn; @@ -982,14 +1012,46 @@ free_use_list (struct use *use) } } +/* Return cover class and number of hard registers (through *NREGS) + for destination of INSN. */ +static enum reg_class +get_cover_class_and_nregs (rtx insn, int *nregs) +{ + rtx reg; + enum reg_class cover_class; + rtx set = single_set (insn); + + /* Considered invariant insns have only one set. */ + gcc_assert (set != NULL_RTX); + reg = SET_DEST (set); + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (MEM_P (reg)) + { + *nregs = 0; + cover_class = NO_REGS; + } + else + { + if (! REG_P (reg)) + reg = NULL_RTX; + if (reg == NULL_RTX) + cover_class = GENERAL_REGS; + else + cover_class = reg_cover_class (REGNO (reg)); + *nregs = ira_reg_class_nregs[cover_class][GET_MODE (SET_SRC (set))]; + } + return cover_class; +} + /* Calculates cost and number of registers needed for moving invariant INV out of the loop and stores them to *COST and *REGS_NEEDED. */ static void get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed) { - int acomp_cost; - unsigned aregs_needed; + int i, acomp_cost; + unsigned aregs_needed[N_REG_CLASSES]; unsigned depno; struct invariant *dep; bitmap_iterator bi; @@ -998,13 +1060,30 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed) inv = VEC_index (invariant_p, invariants, inv->eqto); *comp_cost = 0; - *regs_needed = 0; + if (! flag_ira_loop_pressure) + regs_needed[0] = 0; + else + { + for (i = 0; i < ira_reg_class_cover_size; i++) + regs_needed[ira_reg_class_cover[i]] = 0; + } + if (inv->move || inv->stamp == actual_stamp) return; inv->stamp = actual_stamp; - (*regs_needed)++; + if (! flag_ira_loop_pressure) + regs_needed[0]++; + else + { + int nregs; + enum reg_class cover_class; + + cover_class = get_cover_class_and_nregs (inv->insn, &nregs); + regs_needed[cover_class] += nregs; + } + if (!inv->cheap_address || inv->def->n_addr_uses < inv->def->n_uses) (*comp_cost) += inv->cost; @@ -1029,19 +1108,35 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed) on floating point constants is unlikely to ever occur. */ rtx set = single_set (inv->insn); if (set - && IS_STACK_MODE (GET_MODE (SET_SRC (set))) - && constant_pool_constant_p (SET_SRC (set))) - (*regs_needed) += 2; + && IS_STACK_MODE (GET_MODE (SET_SRC (set))) + && constant_pool_constant_p (SET_SRC (set))) + { + if (flag_ira_loop_pressure) + regs_needed[STACK_REG_COVER_CLASS] += 2; + else + regs_needed[0] += 2; + } } #endif EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, depno, bi) { + bool check_p; + dep = VEC_index (invariant_p, invariants, depno); - get_inv_cost (dep, &acomp_cost, &aregs_needed); + get_inv_cost (dep, &acomp_cost, aregs_needed); - if (aregs_needed + if (! flag_ira_loop_pressure) + check_p = aregs_needed[0] != 0; + else + { + for (i = 0; i < ira_reg_class_cover_size; i++) + if (aregs_needed[ira_reg_class_cover[i]] != 0) + break; + check_p = i < ira_reg_class_cover_size; + } + if (check_p /* We need to check always_executed, since if the original value of the invariant may be preserved, we may need to keep it in a separate register. TODO check whether the register has an @@ -1051,10 +1146,26 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed) { /* If this is a single use, after moving the dependency we will not need a new register. */ - aregs_needed--; + if (! flag_ira_loop_pressure) + aregs_needed[0]--; + else + { + int nregs; + enum reg_class cover_class; + + cover_class = get_cover_class_and_nregs (inv->insn, &nregs); + aregs_needed[cover_class] -= nregs; + } } - (*regs_needed) += aregs_needed; + if (! flag_ira_loop_pressure) + regs_needed[0] += aregs_needed[0]; + else + { + for (i = 0; i < ira_reg_class_cover_size; i++) + regs_needed[ira_reg_class_cover[i]] + += aregs_needed[ira_reg_class_cover[i]]; + } (*comp_cost) += acomp_cost; } } @@ -1066,15 +1177,62 @@ get_inv_cost (struct invariant *inv, int *comp_cost, unsigned *regs_needed) static int gain_for_invariant (struct invariant *inv, unsigned *regs_needed, - unsigned new_regs, unsigned regs_used, bool speed) + unsigned *new_regs, unsigned regs_used, bool speed) { int comp_cost, size_cost; - get_inv_cost (inv, &comp_cost, regs_needed); actual_stamp++; - size_cost = (estimate_reg_pressure_cost (new_regs + *regs_needed, regs_used, speed) - - estimate_reg_pressure_cost (new_regs, regs_used, speed)); + get_inv_cost (inv, &comp_cost, regs_needed); + + if (! flag_ira_loop_pressure) + { + size_cost = (estimate_reg_pressure_cost (new_regs[0] + regs_needed[0], + regs_used, speed) + - estimate_reg_pressure_cost (new_regs[0], + regs_used, speed)); + } + else + { + int i; + enum reg_class cover_class; + + for (i = 0; i < ira_reg_class_cover_size; i++) + { + cover_class = ira_reg_class_cover[i]; + if ((int) new_regs[cover_class] + + (int) regs_needed[cover_class] + + LOOP_DATA (curr_loop)->max_reg_pressure[cover_class] + + IRA_LOOP_RESERVED_REGS + > ira_available_class_regs[cover_class]) + break; + } + if (i < ira_reg_class_cover_size) + /* There will be register pressure excess and we want not to + make this loop invariant motion. All loop invariants with + non-positive gains will be rejected in function + find_invariants_to_move. Therefore we return the negative + number here. + + One could think that this rejects also expensive loop + invariant motions and this will hurt code performance. + However numerous experiments with different heuristics + taking invariant cost into account did not confirm this + assumption. There are possible explanations for this + result: + o probably all expensive invariants were already moved out + of the loop by PRE and gimple invariant motion pass. + o expensive invariant execution will be hidden by insn + scheduling or OOO processor hardware because usually such + invariants have a lot of freedom to be executed + out-of-order. + Another reason for ignoring invariant cost vs spilling cost + heuristics is also in difficulties to evaluate accurately + spill cost at this stage. */ + return -1; + else + size_cost = 0; + } return comp_cost - size_cost; } @@ -1087,11 +1245,11 @@ gain_for_invariant (struct invariant *inv, unsigned *regs_needed, static int best_gain_for_invariant (struct invariant **best, unsigned *regs_needed, - unsigned new_regs, unsigned regs_used, bool speed) + unsigned *new_regs, unsigned regs_used, bool speed) { struct invariant *inv; - int gain = 0, again; - unsigned aregs_needed, invno; + int i, gain = 0, again; + unsigned aregs_needed[N_REG_CLASSES], invno; for (invno = 0; VEC_iterate (invariant_p, invariants, invno, inv); invno++) { @@ -1102,13 +1260,20 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed, if (inv->eqto != inv->invno) continue; - again = gain_for_invariant (inv, &aregs_needed, new_regs, regs_used, + again = gain_for_invariant (inv, aregs_needed, new_regs, regs_used, speed); if (again > gain) { gain = again; *best = inv; - *regs_needed = aregs_needed; + if (! flag_ira_loop_pressure) + regs_needed[0] = aregs_needed[0]; + else + { + for (i = 0; i < ira_reg_class_cover_size; i++) + regs_needed[ira_reg_class_cover[i]] + = aregs_needed[ira_reg_class_cover[i]]; + } } } @@ -1118,7 +1283,7 @@ best_gain_for_invariant (struct invariant **best, unsigned *regs_needed, /* Marks invariant INVNO and all its dependencies for moving. */ static void -set_move_mark (unsigned invno) +set_move_mark (unsigned invno, int gain) { struct invariant *inv = VEC_index (invariant_p, invariants, invno); bitmap_iterator bi; @@ -1131,11 +1296,18 @@ set_move_mark (unsigned invno) inv->move = true; if (dump_file) - fprintf (dump_file, "Decided to move invariant %d\n", invno); + { + if (gain >= 0) + fprintf (dump_file, "Decided to move invariant %d -- gain %d\n", + invno, gain); + else + fprintf (dump_file, "Decided to move dependent invariant %d\n", + invno); + }; EXECUTE_IF_SET_IN_BITMAP (inv->depends_on, 0, invno, bi) { - set_move_mark (invno); + set_move_mark (invno, -1); } } @@ -1144,32 +1316,54 @@ set_move_mark (unsigned invno) static void find_invariants_to_move (bool speed) { - unsigned i, regs_used, regs_needed = 0, new_regs; + int gain; + unsigned i, regs_used, regs_needed[N_REG_CLASSES], new_regs[N_REG_CLASSES]; struct invariant *inv = NULL; - unsigned int n_regs = DF_REG_SIZE (df); if (!VEC_length (invariant_p, invariants)) return; - /* We do not really do a good job in estimating number of registers used; - we put some initial bound here to stand for induction variables etc. - that we do not detect. */ - regs_used = 2; - - for (i = 0; i < n_regs; i++) + if (flag_ira_loop_pressure) + /* REGS_USED is actually never used when the flag is on. */ + regs_used = 0; + else + /* We do not really do a good job in estimating number of + registers used; we put some initial bound here to stand for + induction variables etc. that we do not detect. */ { - if (!DF_REGNO_FIRST_DEF (i) && DF_REGNO_LAST_USE (i)) + unsigned int n_regs = DF_REG_SIZE (df); + + regs_used = 2; + + for (i = 0; i < n_regs; i++) { - /* This is a value that is used but not changed inside loop. */ - regs_used++; + if (!DF_REGNO_FIRST_DEF (i) && DF_REGNO_LAST_USE (i)) + { + /* This is a value that is used but not changed inside loop. */ + regs_used++; + } } } - new_regs = 0; - while (best_gain_for_invariant (&inv, ®s_needed, new_regs, regs_used, speed) > 0) + if (! flag_ira_loop_pressure) + new_regs[0] = regs_needed[0] = 0; + else { - set_move_mark (inv->invno); - new_regs += regs_needed; + for (i = 0; (int) i < ira_reg_class_cover_size; i++) + new_regs[ira_reg_class_cover[i]] = 0; + } + while ((gain = best_gain_for_invariant (&inv, regs_needed, + new_regs, regs_used, speed)) > 0) + { + set_move_mark (inv->invno, gain); + if (! flag_ira_loop_pressure) + new_regs[0] += regs_needed[0]; + else + { + for (i = 0; (int) i < ira_reg_class_cover_size; i++) + new_regs[ira_reg_class_cover[i]] + += regs_needed[ira_reg_class_cover[i]]; + } } } @@ -1186,11 +1380,13 @@ move_invariant_reg (struct loop *loop, unsigned invno) rtx reg, set, dest, note; struct use *use; bitmap_iterator bi; + int regno; if (inv->reg) return true; if (!repr->move) return false; + regno = -1; /* If this is a representative of the class of equivalent invariants, really move the invariant. Otherwise just replace its use with the register used for the representative. */ @@ -1211,7 +1407,12 @@ move_invariant_reg (struct loop *loop, unsigned invno) would not be dominated by it, we may just move it (TODO). Otherwise we need to create a temporary register. */ set = single_set (inv->insn); - dest = SET_DEST (set); + reg = dest = SET_DEST (set); + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + if (REG_P (reg)) + regno = REGNO (reg); + reg = gen_reg_rtx_and_attrs (dest); /* Try replacing the destination by a new pseudoregister. */ @@ -1237,6 +1438,7 @@ move_invariant_reg (struct loop *loop, unsigned invno) if (!move_invariant_reg (loop, repr->invno)) goto fail; reg = repr->reg; + regno = repr->orig_regno; set = single_set (inv->insn); emit_insn_after (gen_move_insn (SET_DEST (set), reg), inv->insn); delete_insn (inv->insn); @@ -1244,6 +1446,7 @@ move_invariant_reg (struct loop *loop, unsigned invno) inv->reg = reg; + inv->orig_regno = regno; /* Replace the uses we know to be dominated. It saves work for copy propagation, and also it is necessary so that dependent invariants @@ -1266,6 +1469,7 @@ fail: fprintf (dump_file, "Failed to move invariant %d\n", invno); inv->move = false; inv->reg = NULL_RTX; + inv->orig_regno = -1; return false; } @@ -1281,6 +1485,21 @@ move_invariants (struct loop *loop) for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++) move_invariant_reg (loop, i); + if (flag_ira_loop_pressure && resize_reg_info ()) + { + for (i = 0; VEC_iterate (invariant_p, invariants, i, inv); i++) + if (inv->reg != NULL_RTX) + { + if (inv->orig_regno >= 0) + setup_reg_classes (REGNO (inv->reg), + reg_preferred_class (inv->orig_regno), + reg_alternate_class (inv->orig_regno), + reg_cover_class (inv->orig_regno)); + else + setup_reg_classes (REGNO (inv->reg), + GENERAL_REGS, NO_REGS, GENERAL_REGS); + } + } } /* Initializes invariant motion data. */ @@ -1346,10 +1565,317 @@ free_loop_data (struct loop *loop) { struct loop_data *data = LOOP_DATA (loop); + bitmap_clear (&LOOP_DATA (loop)->regs_ref); + bitmap_clear (&LOOP_DATA (loop)->regs_live); free (data); loop->aux = NULL; } + + +/* Registers currently living. */ +static bitmap_head curr_regs_live; + +/* Current reg pressure for each cover class. */ +static int curr_reg_pressure[N_REG_CLASSES]; + +/* Record all regs that are set in any one insn. Communication from + mark_reg_{store,clobber} and global_conflicts. Asm can refer to + all hard-registers. */ +static rtx regs_set[(FIRST_PSEUDO_REGISTER > MAX_RECOG_OPERANDS + ? FIRST_PSEUDO_REGISTER : MAX_RECOG_OPERANDS) * 2]; +/* Number of regs stored in the previous array. */ +static int n_regs_set; + +/* Return cover class and number of needed hard registers (through + *NREGS) of register REGNO. */ +static enum reg_class +get_regno_cover_class (int regno, int *nregs) +{ + if (regno >= FIRST_PSEUDO_REGISTER) + { + enum reg_class cover_class = reg_cover_class (regno); + + *nregs = ira_reg_class_nregs[cover_class][PSEUDO_REGNO_MODE (regno)]; + return cover_class; + } + else if (! TEST_HARD_REG_BIT (ira_no_alloc_regs, regno) + && ! TEST_HARD_REG_BIT (eliminable_regset, regno)) + { + *nregs = 1; + return ira_class_translate[REGNO_REG_CLASS (regno)]; + } + else + { + *nregs = 0; + return NO_REGS; + } +} + +/* Increase (if INCR_P) or decrease current register pressure for + register REGNO. */ +static void +change_pressure (int regno, bool incr_p) +{ + int nregs; + enum reg_class cover_class; + + cover_class = get_regno_cover_class (regno, &nregs); + if (! incr_p) + curr_reg_pressure[cover_class] -= nregs; + else + { + curr_reg_pressure[cover_class] += nregs; + if (LOOP_DATA (curr_loop)->max_reg_pressure[cover_class] + < curr_reg_pressure[cover_class]) + LOOP_DATA (curr_loop)->max_reg_pressure[cover_class] + = curr_reg_pressure[cover_class]; + } +} + +/* Mark REGNO birth. */ +static void +mark_regno_live (int regno) +{ + struct loop *loop; + + for (loop = curr_loop; + loop != current_loops->tree_root; + loop = loop_outer (loop)) + bitmap_set_bit (&LOOP_DATA (loop)->regs_live, regno); + if (bitmap_bit_p (&curr_regs_live, regno)) + return; + bitmap_set_bit (&curr_regs_live, regno); + change_pressure (regno, true); +} + +/* Mark REGNO death. */ +static void +mark_regno_death (int regno) +{ + if (! bitmap_bit_p (&curr_regs_live, regno)) + return; + bitmap_clear_bit (&curr_regs_live, regno); + change_pressure (regno, false); +} + +/* Mark setting register REG. */ +static void +mark_reg_store (rtx reg, const_rtx setter ATTRIBUTE_UNUSED, + void *data ATTRIBUTE_UNUSED) +{ + int regno; + + if (GET_CODE (reg) == SUBREG) + reg = SUBREG_REG (reg); + + if (! REG_P (reg)) + return; + + regs_set[n_regs_set++] = reg; + + regno = REGNO (reg); + + if (regno >= FIRST_PSEUDO_REGISTER) + mark_regno_live (regno); + else + { + int last = regno + hard_regno_nregs[regno][GET_MODE (reg)]; + + while (regno < last) + { + mark_regno_live (regno); + regno++; + } + } +} + +/* Mark clobbering register REG. */ +static void +mark_reg_clobber (rtx reg, const_rtx setter, void *data) +{ + if (GET_CODE (setter) == CLOBBER) + mark_reg_store (reg, setter, data); +} + +/* Mark register REG death. */ +static void +mark_reg_death (rtx reg) +{ + int regno = REGNO (reg); + + if (regno >= FIRST_PSEUDO_REGISTER) + mark_regno_death (regno); + else + { + int last = regno + hard_regno_nregs[regno][GET_MODE (reg)]; + + while (regno < last) + { + mark_regno_death (regno); + regno++; + } + } +} + +/* Mark occurrence of registers in X for the current loop. */ +static void +mark_ref_regs (rtx x) +{ + RTX_CODE code; + int i; + const char *fmt; + + if (!x) + return; + + code = GET_CODE (x); + if (code == REG) + { + struct loop *loop; + + for (loop = curr_loop; + loop != current_loops->tree_root; + loop = loop_outer (loop)) + bitmap_set_bit (&LOOP_DATA (loop)->regs_ref, REGNO (x)); + return; + } + + fmt = GET_RTX_FORMAT (code); + for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) + if (fmt[i] == 'e') + mark_ref_regs (XEXP (x, i)); + else if (fmt[i] == 'E') + { + int j; + + for (j = 0; j < XVECLEN (x, i); j++) + mark_ref_regs (XVECEXP (x, i, j)); + } +} + +/* Calculate register pressure in the loops. */ +static void +calculate_loop_reg_pressure (void) +{ + int i; + unsigned int j; + bitmap_iterator bi; + basic_block bb; + rtx insn, link; + struct loop *loop, *parent; + loop_iterator li; + + FOR_EACH_LOOP (li, loop, 0) + if (loop->aux == NULL) + { + loop->aux = xcalloc (1, sizeof (struct loop_data)); + bitmap_initialize (&LOOP_DATA (loop)->regs_ref, ®_obstack); + bitmap_initialize (&LOOP_DATA (loop)->regs_live, ®_obstack); + } + ira_setup_eliminable_regset (); + bitmap_initialize (&curr_regs_live, ®_obstack); + FOR_EACH_BB (bb) + { + curr_loop = bb->loop_father; + if (curr_loop == current_loops->tree_root) + continue; + + for (loop = curr_loop; + loop != current_loops->tree_root; + loop = loop_outer (loop)) + bitmap_ior_into (&LOOP_DATA (loop)->regs_live, DF_LR_IN (bb)); + + bitmap_copy (&curr_regs_live, DF_LR_IN (bb)); + for (i = 0; i < ira_reg_class_cover_size; i++) + curr_reg_pressure[ira_reg_class_cover[i]] = 0; + EXECUTE_IF_SET_IN_BITMAP (&curr_regs_live, 0, j, bi) + change_pressure (j, true); + + FOR_BB_INSNS (bb, insn) + { + if (! NONDEBUG_INSN_P (insn)) + continue; + + mark_ref_regs (PATTERN (insn)); + n_regs_set = 0; + note_stores (PATTERN (insn), mark_reg_clobber, NULL); + + /* Mark any registers dead after INSN as dead now. */ + + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_DEAD) + mark_reg_death (XEXP (link, 0)); + + /* Mark any registers set in INSN as live, + and mark them as conflicting with all other live regs. + Clobbers are processed again, so they conflict with + the registers that are set. */ + + note_stores (PATTERN (insn), mark_reg_store, NULL); + +#ifdef AUTO_INC_DEC + for (link = REG_NOTES (insn); link; link = XEXP (link, 1)) + if (REG_NOTE_KIND (link) == REG_INC) + mark_reg_store (XEXP (link, 0), NULL_RTX, NULL); +#endif + while (n_regs_set-- > 0) + { + rtx note = find_regno_note (insn, REG_UNUSED, + REGNO (regs_set[n_regs_set])); + if (! note) + continue; + + mark_reg_death (XEXP (note, 0)); + } + } + } + bitmap_clear (&curr_regs_live); + if (flag_ira_region == IRA_REGION_MIXED + || flag_ira_region == IRA_REGION_ALL) + FOR_EACH_LOOP (li, loop, 0) + { + EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_live, 0, j, bi) + if (! bitmap_bit_p (&LOOP_DATA (loop)->regs_ref, j)) + { + enum reg_class cover_class; + int nregs; + + cover_class = get_regno_cover_class (j, &nregs); + LOOP_DATA (loop)->max_reg_pressure[cover_class] -= nregs; + } + } + if (dump_file == NULL) + return; + FOR_EACH_LOOP (li, loop, 0) + { + parent = loop_outer (loop); + fprintf (dump_file, "\n Loop %d (parent %d, header bb%d, depth %d)\n", + loop->num, (parent == NULL ? -1 : parent->num), + loop->header->index, loop_depth (loop)); + fprintf (dump_file, "\n ref. regnos:"); + EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_ref, 0, j, bi) + fprintf (dump_file, " %d", j); + fprintf (dump_file, "\n live regnos:"); + EXECUTE_IF_SET_IN_BITMAP (&LOOP_DATA (loop)->regs_live, 0, j, bi) + fprintf (dump_file, " %d", j); + fprintf (dump_file, "\n Pressure:"); + for (i = 0; (int) i < ira_reg_class_cover_size; i++) + { + enum reg_class cover_class; + + cover_class = ira_reg_class_cover[i]; + if (LOOP_DATA (loop)->max_reg_pressure[cover_class] == 0) + continue; + fprintf (dump_file, " %s=%d", reg_class_names[cover_class], + LOOP_DATA (loop)->max_reg_pressure[cover_class]); + } + fprintf (dump_file, "\n"); + } +} + + + /* Move the invariants out of the loops. */ void @@ -1358,10 +1884,17 @@ move_loop_invariants (void) struct loop *loop; loop_iterator li; + if (flag_ira_loop_pressure) + { + df_analyze (); + ira_set_pseudo_classes (dump_file); + calculate_loop_reg_pressure (); + } df_set_flags (DF_EQ_NOTES + DF_DEFER_INSN_RESCAN); /* Process the loops, innermost first. */ FOR_EACH_LOOP (li, loop, LI_FROM_INNERMOST) { + curr_loop = loop; /* move_single_loop_invariants for very large loops is time consuming and might need a lot of memory. */ if (loop->num_nodes <= (unsigned) LOOP_INVARIANT_MAX_BBS_IN_LOOP) @@ -1373,6 +1906,10 @@ move_loop_invariants (void) free_loop_data (loop); } + if (flag_ira_loop_pressure) + /* There is no sense to keep this info because it was most + probably outdated by subsequent passes. */ + free_reg_info (); free (invariant_table); invariant_table = NULL; invariant_table_size = 0; diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c new file mode 100644 index 00000000000..6b340a37d58 --- /dev/null +++ b/gcc/lto-cgraph.c @@ -0,0 +1,687 @@ +/* Write and read the cgraph to the memory mapped representation of a + .o file. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Kenneth Zadeck + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "tree.h" +#include "expr.h" +#include "flags.h" +#include "params.h" +#include "input.h" +#include "varray.h" +#include "hashtab.h" +#include "langhooks.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "cgraph.h" +#include "function.h" +#include "ggc.h" +#include "diagnostic.h" +#include "except.h" +#include "vec.h" +#include "timevar.h" +#include "output.h" +#include "pointer-set.h" +#include "lto-streamer.h" + +/* Create a new cgraph encoder. */ + +lto_cgraph_encoder_t +lto_cgraph_encoder_new (void) +{ + lto_cgraph_encoder_t encoder = XCNEW (struct lto_cgraph_encoder_d); + encoder->map = pointer_map_create (); + encoder->nodes = NULL; + return encoder; +} + + +/* Delete ENCODER and its components. */ + +void +lto_cgraph_encoder_delete (lto_cgraph_encoder_t encoder) +{ + VEC_free (cgraph_node_ptr, heap, encoder->nodes); + pointer_map_destroy (encoder->map); + free (encoder); +} + + +/* Return the existing reference number of NODE in the cgraph encoder in + output block OB. Assign a new reference if this is the first time + NODE is encoded. */ + +int +lto_cgraph_encoder_encode (lto_cgraph_encoder_t encoder, + struct cgraph_node *node) +{ + int ref; + void **slot; + + slot = pointer_map_contains (encoder->map, node); + if (!slot) + { + ref = VEC_length (cgraph_node_ptr, encoder->nodes); + slot = pointer_map_insert (encoder->map, node); + *slot = (void *) (intptr_t) ref; + VEC_safe_push (cgraph_node_ptr, heap, encoder->nodes, node); + } + else + ref = (int) (intptr_t) *slot; + + return ref; +} + + +/* Look up NODE in encoder. Return NODE's reference if it has been encoded + or LCC_NOT_FOUND if it is not there. */ + +int +lto_cgraph_encoder_lookup (lto_cgraph_encoder_t encoder, + struct cgraph_node *node) +{ + void **slot = pointer_map_contains (encoder->map, node); + return (slot ? (int) (intptr_t) *slot : LCC_NOT_FOUND); +} + + +/* Return the cgraph node corresponding to REF using ENCODER. */ + +struct cgraph_node * +lto_cgraph_encoder_deref (lto_cgraph_encoder_t encoder, int ref) +{ + if (ref == LCC_NOT_FOUND) + return NULL; + + return VEC_index (cgraph_node_ptr, encoder->nodes, ref); +} + + +/* Return number of encoded nodes in ENCODER. */ + +static int +lto_cgraph_encoder_size (lto_cgraph_encoder_t encoder) +{ + return VEC_length (cgraph_node_ptr, encoder->nodes); +} + + +/* Output the cgraph EDGE to OB using ENCODER. */ + +static void +lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge, + lto_cgraph_encoder_t encoder) +{ + unsigned int uid; + intptr_t ref; + struct bitpack_d *bp; + + lto_output_uleb128_stream (ob->main_stream, LTO_cgraph_edge); + + ref = lto_cgraph_encoder_lookup (encoder, edge->caller); + gcc_assert (ref != LCC_NOT_FOUND); + lto_output_sleb128_stream (ob->main_stream, ref); + + ref = lto_cgraph_encoder_lookup (encoder, edge->callee); + gcc_assert (ref != LCC_NOT_FOUND); + lto_output_sleb128_stream (ob->main_stream, ref); + + lto_output_sleb128_stream (ob->main_stream, edge->count); + + bp = bitpack_create (); + uid = flag_wpa ? edge->lto_stmt_uid : gimple_uid (edge->call_stmt); + bp_pack_value (bp, uid, HOST_BITS_PER_INT); + bp_pack_value (bp, edge->inline_failed, HOST_BITS_PER_INT); + bp_pack_value (bp, edge->frequency, HOST_BITS_PER_INT); + bp_pack_value (bp, edge->loop_nest, 30); + bp_pack_value (bp, edge->indirect_call, 1); + bp_pack_value (bp, edge->call_stmt_cannot_inline_p, 1); + bp_pack_value (bp, edge->can_throw_external, 1); + lto_output_bitpack (ob->main_stream, bp); + bitpack_delete (bp); +} + + +/* Output the cgraph NODE to OB. ENCODER is used to find the + reference number of NODE->inlined_to. SET is the set of nodes we + are writing to the current file. If NODE is not in SET, then NODE + is a boundary of a cgraph_node_set and we pretend NODE just has a + decl and no callees. WRITTEN_DECLS is the set of FUNCTION_DECLs + that have had their callgraph node written so far. This is used to + determine if NODE is a clone of a previously written node. */ + +static void +lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, + lto_cgraph_encoder_t encoder, cgraph_node_set set, + bitmap written_decls) +{ + unsigned int tag; + struct bitpack_d *bp; + unsigned local, externally_visible, inlinable, analyzed; + bool boundary_p, wrote_decl_p; + intptr_t ref; + + boundary_p = !cgraph_node_in_set_p (node, set); + wrote_decl_p = bitmap_bit_p (written_decls, DECL_UID (node->decl)); + + switch (cgraph_function_body_availability (node)) + { + case AVAIL_NOT_AVAILABLE: + tag = LTO_cgraph_unavail_node; + break; + + case AVAIL_AVAILABLE: + case AVAIL_LOCAL: + tag = LTO_cgraph_avail_node; + break; + + case AVAIL_OVERWRITABLE: + tag = LTO_cgraph_overwritable_node; + break; + + default: + gcc_unreachable (); + } + + if (boundary_p) + tag = LTO_cgraph_unavail_node; + + lto_output_uleb128_stream (ob->main_stream, tag); + + local = node->local.local; + externally_visible = node->local.externally_visible; + inlinable = node->local.inlinable; + analyzed = node->analyzed; + + /* In WPA mode, we only output part of the call-graph. Also, we + fake cgraph node attributes. There are two cases that we care. + + Boundary nodes: There are nodes that are not part of SET but are + called from within SET. We artificially make them look like + externally visible nodes with no function body. + + Cherry-picked nodes: These are nodes we pulled from other + translation units into SET during IPA-inlining. We make them as + local static nodes to prevent clashes with other local statics. */ + if (boundary_p) + { + /* Inline clones can not be part of boundary. */ + gcc_assert (!node->global.inlined_to); + local = 0; + externally_visible = 1; + inlinable = 0; + analyzed = 0; + } + else if (lto_forced_extern_inline_p (node->decl)) + { + local = 1; + externally_visible = 0; + inlinable = 1; + } + + lto_output_uleb128_stream (ob->main_stream, wrote_decl_p); + + if (!wrote_decl_p) + bitmap_set_bit (written_decls, DECL_UID (node->decl)); + + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->decl); + lto_output_sleb128_stream (ob->main_stream, node->count); + + bp = bitpack_create (); + bp_pack_value (bp, local, 1); + bp_pack_value (bp, externally_visible, 1); + bp_pack_value (bp, node->local.finalized, 1); + bp_pack_value (bp, inlinable, 1); + bp_pack_value (bp, node->local.disregard_inline_limits, 1); + bp_pack_value (bp, node->local.redefined_extern_inline, 1); + bp_pack_value (bp, node->local.for_functions_valid, 1); + bp_pack_value (bp, node->local.vtable_method, 1); + bp_pack_value (bp, node->needed, 1); + bp_pack_value (bp, node->address_taken, 1); + bp_pack_value (bp, node->abstract_and_needed, 1); + bp_pack_value (bp, node->reachable, 1); + bp_pack_value (bp, node->lowered, 1); + bp_pack_value (bp, analyzed, 1); + bp_pack_value (bp, node->process, 1); + bp_pack_value (bp, node->alias, 1); + bp_pack_value (bp, node->finalized_by_frontend, 1); + lto_output_bitpack (ob->main_stream, bp); + bitpack_delete (bp); + + if (tag != LTO_cgraph_unavail_node) + { + lto_output_sleb128_stream (ob->main_stream, + node->local.inline_summary.estimated_self_stack_size); + lto_output_sleb128_stream (ob->main_stream, + node->local.inline_summary.self_size); + lto_output_sleb128_stream (ob->main_stream, + node->local.inline_summary.size_inlining_benefit); + lto_output_sleb128_stream (ob->main_stream, + node->local.inline_summary.self_time); + lto_output_sleb128_stream (ob->main_stream, + node->local.inline_summary.time_inlining_benefit); + } + + /* FIXME lto: Outputting global info is not neccesary until after + inliner was run. Global structure holds results of propagation + done by inliner. */ + lto_output_sleb128_stream (ob->main_stream, + node->global.estimated_stack_size); + lto_output_sleb128_stream (ob->main_stream, + node->global.stack_frame_offset); + if (node->global.inlined_to && !boundary_p) + { + ref = lto_cgraph_encoder_lookup (encoder, node->global.inlined_to); + gcc_assert (ref != LCC_NOT_FOUND); + } + else + ref = LCC_NOT_FOUND; + lto_output_sleb128_stream (ob->main_stream, ref); + + lto_output_sleb128_stream (ob->main_stream, node->global.time); + lto_output_sleb128_stream (ob->main_stream, node->global.size); + lto_output_sleb128_stream (ob->main_stream, + node->global.estimated_growth); + lto_output_uleb128_stream (ob->main_stream, node->global.inlined); +} + + +/* Output the part of the cgraph in SET. */ + +void +output_cgraph (cgraph_node_set set) +{ + struct cgraph_node *node; + struct lto_simple_output_block *ob; + cgraph_node_set_iterator csi; + struct cgraph_edge *edge; + int i, n_nodes; + bitmap written_decls; + lto_cgraph_encoder_t encoder; + struct cgraph_asm_node *can; + + ob = lto_create_simple_output_block (LTO_section_cgraph); + + /* An encoder for cgraph nodes should have been created by + ipa_write_summaries_1. */ + gcc_assert (ob->decl_state->cgraph_node_encoder); + encoder = ob->decl_state->cgraph_node_encoder; + + /* The FUNCTION_DECLs for which we have written a node. The first + node found is written as the "original" node, the remaining nodes + are considered its clones. */ + written_decls = lto_bitmap_alloc (); + + /* Go over all the nodes in SET and assign references. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + lto_cgraph_encoder_encode (encoder, node); + } + + /* Go over all the nodes again to include callees that are not in + SET. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + for (edge = node->callees; edge; edge = edge->next_callee) + { + struct cgraph_node *callee = edge->callee; + if (!cgraph_node_in_set_p (callee, set)) + { + /* We should have moved all the inlines. */ + gcc_assert (!callee->global.inlined_to); + lto_cgraph_encoder_encode (encoder, callee); + } + } + } + + /* Write out the nodes. */ + n_nodes = lto_cgraph_encoder_size (encoder); + for (i = 0; i < n_nodes; i++) + { + node = lto_cgraph_encoder_deref (encoder, i); + lto_output_node (ob, node, encoder, set, written_decls); + } + + lto_bitmap_free (written_decls); + + /* Go over the nodes in SET again to write edges. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (node->callees) + { + /* Output edges in backward direction, so the reconstructed callgraph + match and it is easy to associate call sites in the IPA pass summaries. */ + edge = node->callees; + while (edge->next_callee) + edge = edge->next_callee; + for (; edge; edge = edge->prev_callee) + lto_output_edge (ob, edge, encoder); + } + } + + lto_output_uleb128_stream (ob->main_stream, 0); + + /* Emit toplevel asms. */ + for (can = cgraph_asm_nodes; can; can = can->next) + { + int len = TREE_STRING_LENGTH (can->asm_str); + lto_output_uleb128_stream (ob->main_stream, len); + for (i = 0; i < len; ++i) + lto_output_1_stream (ob->main_stream, + TREE_STRING_POINTER (can->asm_str)[i]); + } + + lto_output_uleb128_stream (ob->main_stream, 0); + + lto_destroy_simple_output_block (ob); +} + + +/* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS, + STACK_SIZE, SELF_TIME and SELF_SIZE. This is called either to initialize + NODE or to replace the values in it, for instance because the first + time we saw it, the function body was not available but now it + is. BP is a bitpack with all the bitflags for NODE read from the + stream. */ + +static void +input_overwrite_node (struct lto_file_decl_data *file_data, + struct cgraph_node *node, + enum LTO_cgraph_tags tag, + struct bitpack_d *bp, + unsigned int stack_size, + unsigned int self_time, + unsigned int time_inlining_benefit, + unsigned int self_size, + unsigned int size_inlining_benefit) +{ + node->aux = (void *) tag; + node->local.inline_summary.estimated_self_stack_size = stack_size; + node->local.inline_summary.self_time = self_time; + node->local.inline_summary.time_inlining_benefit = time_inlining_benefit; + node->local.inline_summary.self_size = self_size; + node->local.inline_summary.size_inlining_benefit = size_inlining_benefit; + node->global.time = self_time; + node->global.size = self_size; + node->local.lto_file_data = file_data; + + node->local.local = bp_unpack_value (bp, 1); + node->local.externally_visible = bp_unpack_value (bp, 1); + node->local.finalized = bp_unpack_value (bp, 1); + node->local.inlinable = bp_unpack_value (bp, 1); + node->local.disregard_inline_limits = bp_unpack_value (bp, 1); + node->local.redefined_extern_inline = bp_unpack_value (bp, 1); + node->local.for_functions_valid = bp_unpack_value (bp, 1); + node->local.vtable_method = bp_unpack_value (bp, 1); + node->needed = bp_unpack_value (bp, 1); + node->address_taken = bp_unpack_value (bp, 1); + node->abstract_and_needed = bp_unpack_value (bp, 1); + node->reachable = bp_unpack_value (bp, 1); + node->lowered = bp_unpack_value (bp, 1); + node->analyzed = bp_unpack_value (bp, 1); + node->process = bp_unpack_value (bp, 1); + node->alias = bp_unpack_value (bp, 1); + node->finalized_by_frontend = bp_unpack_value (bp, 1); +} + + +/* Read a node from input_block IB. TAG is the node's tag just read. + Return the node read or overwriten. */ + +static struct cgraph_node * +input_node (struct lto_file_decl_data *file_data, + struct lto_input_block *ib, + enum LTO_cgraph_tags tag) +{ + tree fn_decl; + struct cgraph_node *node; + struct bitpack_d *bp; + int stack_size = 0; + unsigned decl_index; + bool clone_p; + int estimated_stack_size = 0; + int stack_frame_offset = 0; + int ref = LCC_NOT_FOUND; + int estimated_growth = 0; + int time = 0; + int size = 0; + int self_time = 0; + int self_size = 0; + int time_inlining_benefit = 0; + int size_inlining_benefit = 0; + bool inlined = false; + + clone_p = (lto_input_uleb128 (ib) != 0); + + decl_index = lto_input_uleb128 (ib); + fn_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index); + + if (clone_p) + node = cgraph_clone_node (cgraph_node (fn_decl), 0, + CGRAPH_FREQ_BASE, 0, false, NULL); + + else + node = cgraph_node (fn_decl); + + node->count = lto_input_sleb128 (ib); + bp = lto_input_bitpack (ib); + + if (tag != LTO_cgraph_unavail_node) + { + stack_size = lto_input_sleb128 (ib); + self_size = lto_input_sleb128 (ib); + size_inlining_benefit = lto_input_sleb128 (ib); + self_time = lto_input_sleb128 (ib); + time_inlining_benefit = lto_input_sleb128 (ib); + } + + estimated_stack_size = lto_input_sleb128 (ib); + stack_frame_offset = lto_input_sleb128 (ib); + ref = lto_input_sleb128 (ib); + time = lto_input_sleb128 (ib); + size = lto_input_sleb128 (ib); + estimated_growth = lto_input_sleb128 (ib); + inlined = lto_input_uleb128 (ib); + + /* Make sure that we have not read this node before. Nodes that + have already been read will have their tag stored in the 'aux' + field. Since built-in functions can be referenced in multiple + functions, they are expected to be read more than once. */ + if (node->aux && !DECL_IS_BUILTIN (node->decl)) + internal_error ("bytecode stream: found multiple instances of cgraph " + "node %d", node->uid); + + input_overwrite_node (file_data, node, tag, bp, stack_size, self_time, + time_inlining_benefit, self_size, + size_inlining_benefit); + bitpack_delete (bp); + + node->global.estimated_stack_size = estimated_stack_size; + node->global.stack_frame_offset = stack_frame_offset; + node->global.time = time; + node->global.size = size; + + /* Store a reference for now, and fix up later to be a pointer. */ + node->global.inlined_to = (cgraph_node_ptr) (intptr_t) ref; + + node->global.estimated_growth = estimated_growth; + node->global.inlined = inlined; + + return node; +} + + +/* Read an edge from IB. NODES points to a vector of previously read + nodes for decoding caller and callee of the edge to be read. */ + +static void +input_edge (struct lto_input_block *ib, VEC(cgraph_node_ptr, heap) *nodes) +{ + struct cgraph_node *caller, *callee; + struct cgraph_edge *edge; + unsigned int stmt_id; + gcov_type count; + int freq; + unsigned int nest; + cgraph_inline_failed_t inline_failed; + struct bitpack_d *bp; + enum ld_plugin_symbol_resolution caller_resolution; + + caller = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib)); + if (caller == NULL || caller->decl == NULL_TREE) + internal_error ("bytecode stream: no caller found while reading edge"); + + callee = VEC_index (cgraph_node_ptr, nodes, lto_input_sleb128 (ib)); + if (callee == NULL || callee->decl == NULL_TREE) + internal_error ("bytecode stream: no callee found while reading edge"); + + count = (gcov_type) lto_input_sleb128 (ib); + + bp = lto_input_bitpack (ib); + stmt_id = (unsigned int) bp_unpack_value (bp, HOST_BITS_PER_INT); + inline_failed = (cgraph_inline_failed_t) bp_unpack_value (bp, + HOST_BITS_PER_INT); + freq = (int) bp_unpack_value (bp, HOST_BITS_PER_INT); + nest = (unsigned) bp_unpack_value (bp, 30); + + /* If the caller was preempted, don't create the edge. + ??? Should we ever have edges from a preempted caller? */ + caller_resolution = lto_symtab_get_resolution (caller->decl); + if (caller_resolution == LDPR_PREEMPTED_REG + || caller_resolution == LDPR_PREEMPTED_IR) + return; + + edge = cgraph_create_edge (caller, callee, NULL, count, freq, nest); + edge->lto_stmt_uid = stmt_id; + edge->inline_failed = inline_failed; + edge->indirect_call = bp_unpack_value (bp, 1); + edge->call_stmt_cannot_inline_p = bp_unpack_value (bp, 1); + edge->can_throw_external = bp_unpack_value (bp, 1); + bitpack_delete (bp); +} + + +/* Read a cgraph from IB using the info in FILE_DATA. */ + +static void +input_cgraph_1 (struct lto_file_decl_data *file_data, + struct lto_input_block *ib) +{ + enum LTO_cgraph_tags tag; + VEC(cgraph_node_ptr, heap) *nodes = NULL; + struct cgraph_node *node; + unsigned i; + unsigned HOST_WIDE_INT len; + + tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib); + while (tag) + { + if (tag == LTO_cgraph_edge) + input_edge (ib, nodes); + else + { + node = input_node (file_data, ib, tag); + if (node == NULL || node->decl == NULL_TREE) + internal_error ("bytecode stream: found empty cgraph node"); + VEC_safe_push (cgraph_node_ptr, heap, nodes, node); + lto_cgraph_encoder_encode (file_data->cgraph_node_encoder, node); + } + + tag = (enum LTO_cgraph_tags) lto_input_uleb128 (ib); + } + + /* Input toplevel asms. */ + len = lto_input_uleb128 (ib); + while (len) + { + char *str = (char *)xmalloc (len + 1); + for (i = 0; i < len; ++i) + str[i] = lto_input_1_unsigned (ib); + cgraph_add_asm_node (build_string (len, str)); + free (str); + + len = lto_input_uleb128 (ib); + } + + for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++) + { + const int ref = (int) (intptr_t) node->global.inlined_to; + + /* Fixup inlined_to from reference to pointer. */ + if (ref != LCC_NOT_FOUND) + node->global.inlined_to = VEC_index (cgraph_node_ptr, nodes, ref); + else + node->global.inlined_to = NULL; + } + + VEC_free (cgraph_node_ptr, heap, nodes); +} + + +/* Input and merge the cgraph from each of the .o files passed to + lto1. */ + +void +input_cgraph (void) +{ + struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); + struct lto_file_decl_data *file_data; + unsigned int j = 0; + struct cgraph_node *node; + + while ((file_data = file_data_vec[j++])) + { + const char *data; + size_t len; + struct lto_input_block *ib; + + ib = lto_create_simple_input_block (file_data, LTO_section_cgraph, + &data, &len); + file_data->cgraph_node_encoder = lto_cgraph_encoder_new (); + input_cgraph_1 (file_data, ib); + lto_destroy_simple_input_block (file_data, LTO_section_cgraph, + ib, data, len); + + /* Assume that every file read needs to be processed by LTRANS. */ + if (flag_wpa) + lto_mark_file_for_ltrans (file_data); + } + + /* Clear out the aux field that was used to store enough state to + tell which nodes should be overwritten. */ + for (node = cgraph_nodes; node; node = node->next) + { + /* Some nodes may have been created by cgraph_node. This + happens when the callgraph contains nested functions. If the + node for the parent function was never emitted to the gimple + file, cgraph_node will create a node for it when setting the + context of the nested function. */ + if (node->local.lto_file_data) + node->aux = NULL; + } +} diff --git a/gcc/lto-compress.c b/gcc/lto-compress.c new file mode 100644 index 00000000000..8d745f6a047 --- /dev/null +++ b/gcc/lto-compress.c @@ -0,0 +1,314 @@ +/* LTO IL compression streams. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Simon Baldwin + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +/* zlib.h includes other system headers. Those headers may test feature + test macros. config.h may define feature test macros. For this reason, + zlib.h needs to be included after, rather than before, config.h and + system.h. */ +#include +#include "coretypes.h" +#include "tree.h" +#include "diagnostic.h" +#include "errors.h" +#include "langhooks.h" +#include "lto-streamer.h" +#include "lto-compress.h" + +/* Compression stream structure, holds the flush callback and opaque token, + the buffered data, and a note of whether compressing or uncompressing. */ + +struct lto_compression_stream +{ + void (*callback) (const char *, unsigned, void *); + void *opaque; + char *buffer; + size_t bytes; + size_t allocation; + bool is_compression; +}; + +/* Overall compression constants for zlib. */ + +static const size_t Z_BUFFER_LENGTH = 4096; +static const size_t MIN_STREAM_ALLOCATION = 1024; + +/* For zlib, allocate SIZE count of ITEMS and return the address, OPAQUE + is unused. */ + +static void * +lto_zalloc (void *opaque, unsigned items, unsigned size) +{ + gcc_assert (opaque == Z_NULL); + return xmalloc (items * size); +} + +/* For zlib, free memory at ADDRESS, OPAQUE is unused. */ + +static void +lto_zfree (void *opaque, void *address) +{ + gcc_assert (opaque == Z_NULL); + free (address); +} + +/* Return a zlib compression level that zlib will not reject. Normalizes + the compression level from the command line flag, clamping non-default + values to the appropriate end of their valid range. */ + +static int +lto_normalized_zlib_level (void) +{ + int level = flag_lto_compression_level; + + if (level != Z_DEFAULT_COMPRESSION) + { + if (level < Z_NO_COMPRESSION) + level = Z_NO_COMPRESSION; + else if (level > Z_BEST_COMPRESSION) + level = Z_BEST_COMPRESSION; + } + + return level; +} + +/* Create a new compression stream, with CALLBACK flush function passed + OPAQUE token, IS_COMPRESSION indicates if compressing or uncompressing. */ + +static struct lto_compression_stream * +lto_new_compression_stream (void (*callback) (const char *, unsigned, void *), + void *opaque, bool is_compression) +{ + struct lto_compression_stream *stream + = (struct lto_compression_stream *) xmalloc (sizeof (*stream)); + + memset (stream, 0, sizeof (*stream)); + stream->callback = callback; + stream->opaque = opaque; + stream->is_compression = is_compression; + + return stream; +} + +/* Append NUM_CHARS from address BASE to STREAM. */ + +static void +lto_append_to_compression_stream (struct lto_compression_stream *stream, + const char *base, size_t num_chars) +{ + size_t required = stream->bytes + num_chars; + + if (stream->allocation < required) + { + if (stream->allocation == 0) + stream->allocation = MIN_STREAM_ALLOCATION; + while (stream->allocation < required) + stream->allocation *= 2; + + stream->buffer = (char *) xrealloc (stream->buffer, stream->allocation); + } + + memcpy (stream->buffer + stream->bytes, base, num_chars); + stream->bytes += num_chars; +} + +/* Free the buffer and memory associated with STREAM. */ + +static void +lto_destroy_compression_stream (struct lto_compression_stream *stream) +{ + free (stream->buffer); + free (stream); +} + +/* Return a new compression stream, with CALLBACK flush function passed + OPAQUE token. */ + +struct lto_compression_stream * +lto_start_compression (void (*callback) (const char *, unsigned, void *), + void *opaque) +{ + return lto_new_compression_stream (callback, opaque, true); +} + +/* Append NUM_CHARS from address BASE to STREAM. */ + +void +lto_compress_block (struct lto_compression_stream *stream, + const char *base, size_t num_chars) +{ + gcc_assert (stream->is_compression); + + lto_append_to_compression_stream (stream, base, num_chars); + lto_stats.num_output_il_bytes += num_chars; +} + +/* Finalize STREAM compression, and free stream allocations. */ + +void +lto_end_compression (struct lto_compression_stream *stream) +{ + unsigned char *cursor = (unsigned char *) stream->buffer; + size_t remaining = stream->bytes; + const size_t outbuf_length = Z_BUFFER_LENGTH; + unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length); + z_stream out_stream; + size_t compressed_bytes = 0; + int status; + + gcc_assert (stream->is_compression); + + out_stream.next_out = outbuf; + out_stream.avail_out = outbuf_length; + out_stream.next_in = cursor; + out_stream.avail_in = remaining; + out_stream.zalloc = lto_zalloc; + out_stream.zfree = lto_zfree; + out_stream.opaque = Z_NULL; + + status = deflateInit (&out_stream, lto_normalized_zlib_level ()); + if (status != Z_OK) + internal_error ("compressed stream: %s", zError (status)); + + do + { + size_t in_bytes, out_bytes; + + status = deflate (&out_stream, Z_FINISH); + if (status != Z_OK && status != Z_STREAM_END) + internal_error ("compressed stream: %s", zError (status)); + + in_bytes = remaining - out_stream.avail_in; + out_bytes = outbuf_length - out_stream.avail_out; + + stream->callback ((const char *) outbuf, out_bytes, stream->opaque); + lto_stats.num_compressed_il_bytes += out_bytes; + compressed_bytes += out_bytes; + + cursor += in_bytes; + remaining -= in_bytes; + + out_stream.next_out = outbuf; + out_stream.avail_out = outbuf_length; + out_stream.next_in = cursor; + out_stream.avail_in = remaining; + } + while (status != Z_STREAM_END); + + status = deflateEnd (&out_stream); + if (status != Z_OK) + internal_error ("compressed stream: %s", zError (status)); + + lto_destroy_compression_stream (stream); + free (outbuf); +} + +/* Return a new uncompression stream, with CALLBACK flush function passed + OPAQUE token. */ + +struct lto_compression_stream * +lto_start_uncompression (void (*callback) (const char *, unsigned, void *), + void *opaque) +{ + return lto_new_compression_stream (callback, opaque, false); +} + +/* Append NUM_CHARS from address BASE to STREAM. */ + +void +lto_uncompress_block (struct lto_compression_stream *stream, + const char *base, size_t num_chars) +{ + gcc_assert (!stream->is_compression); + + lto_append_to_compression_stream (stream, base, num_chars); + lto_stats.num_input_il_bytes += num_chars; +} + +/* Finalize STREAM uncompression, and free stream allocations. + + Because of the way LTO IL streams are compressed, there may be several + concatenated compressed segments in the accumulated data, so for this + function we iterate decompressions until no data remains. */ + +void +lto_end_uncompression (struct lto_compression_stream *stream) +{ + unsigned char *cursor = (unsigned char *) stream->buffer; + size_t remaining = stream->bytes; + const size_t outbuf_length = Z_BUFFER_LENGTH; + unsigned char *outbuf = (unsigned char *) xmalloc (outbuf_length); + size_t uncompressed_bytes = 0; + + gcc_assert (!stream->is_compression); + + while (remaining > 0) + { + z_stream in_stream; + size_t out_bytes; + int status; + + in_stream.next_out = outbuf; + in_stream.avail_out = outbuf_length; + in_stream.next_in = cursor; + in_stream.avail_in = remaining; + in_stream.zalloc = lto_zalloc; + in_stream.zfree = lto_zfree; + in_stream.opaque = Z_NULL; + + status = inflateInit (&in_stream); + if (status != Z_OK) + internal_error ("compressed stream: %s", zError (status)); + + do + { + size_t in_bytes; + + status = inflate (&in_stream, Z_SYNC_FLUSH); + if (status != Z_OK && status != Z_STREAM_END) + internal_error ("compressed stream: %s", zError (status)); + + in_bytes = remaining - in_stream.avail_in; + out_bytes = outbuf_length - in_stream.avail_out; + + stream->callback ((const char *) outbuf, out_bytes, stream->opaque); + lto_stats.num_uncompressed_il_bytes += out_bytes; + uncompressed_bytes += out_bytes; + + cursor += in_bytes; + remaining -= in_bytes; + + in_stream.next_out = outbuf; + in_stream.avail_out = outbuf_length; + in_stream.next_in = cursor; + in_stream.avail_in = remaining; + } + while (!(status == Z_STREAM_END && out_bytes == 0)); + + status = inflateEnd (&in_stream); + if (status != Z_OK) + internal_error ("compressed stream: %s", zError (status)); + } + + lto_destroy_compression_stream (stream); + free (outbuf); +} diff --git a/gcc/lto-compress.h b/gcc/lto-compress.h new file mode 100644 index 00000000000..566a73498d2 --- /dev/null +++ b/gcc/lto-compress.h @@ -0,0 +1,42 @@ +/* LTO IL compression streams. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Simon Baldwin + +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 3, 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 COPYING3. If not see +. */ + +#ifndef GCC_LTO_COMPRESS_H +#define GCC_LTO_COMPRESS_H + +struct lto_compression_stream; + +/* In lto-compress.c. */ +extern struct lto_compression_stream + *lto_start_compression (void (*callback) (const char *, unsigned, void *), + void *opaque); +extern void lto_compress_block (struct lto_compression_stream *stream, + const char *base, size_t num_chars); +extern void lto_end_compression (struct lto_compression_stream *stream); + +extern struct lto_compression_stream + *lto_start_uncompression (void (*callback) (const char *, unsigned, void *), + void *opaque); +extern void lto_uncompress_block (struct lto_compression_stream *stream, + const char *base, size_t num_chars); +extern void lto_end_uncompression (struct lto_compression_stream *stream); + +#endif /* GCC_LTO_COMPRESS_H */ diff --git a/gcc/lto-opts.c b/gcc/lto-opts.c new file mode 100644 index 00000000000..fd485b9db60 --- /dev/null +++ b/gcc/lto-opts.c @@ -0,0 +1,397 @@ +/* LTO IL options. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Simon Baldwin + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tree.h" +#include "hashtab.h" +#include "ggc.h" +#include "vec.h" +#include "bitmap.h" +#include "flags.h" +#include "opts.h" +#include "options.h" +#include "target.h" +#include "toplev.h" +#include "lto-streamer.h" + +/* When a file is initially compiled, the options used when generating + the IL are not necessarily the same as those used when linking the + objects into the final executable. In general, most build systems + will proceed with something along the lines of: + + $ gcc -flto -c f1.c -o f1.o + $ gcc -flto -c f2.c -o f2.o + ... + $ gcc -flto -c fN.c -o fN.o + + And the final link may or may not include the same used + to generate the initial object files: + + $ gcc -flto -o prog f1.o ... fN.o + + Since we will be generating final code during the link step, some + of the flags used during the compile step need to be re-applied + during the link step. For instance, flags in the -m family. + + The idea is to save a selected set of in a special + section of the initial object files. This section is then read + during linking and the options re-applied. + + FIXME lto. Currently the scheme is limited in that only the + options saved on the first object file (f1.o) are read back during + the link step. This means that the options used to compile f1.o + will be applied to ALL the object files in the final link step. + More work needs to be done to implement a merging and validation + mechanism, as this will not be enough for all cases. */ + +/* Saved options hold the type of the option (currently CL_TARGET or + CL_COMMON), and the code, argument, and value. */ + +typedef struct GTY(()) opt_d +{ + unsigned int type; + size_t code; + char *arg; + int value; +} opt_t; + +DEF_VEC_O (opt_t); +DEF_VEC_ALLOC_O (opt_t, heap); + + +/* Options are held in two vectors, one for those registered by + command line handling code, and the other for those read in from + any LTO IL input. */ +static VEC(opt_t, heap) *user_options = NULL; +static VEC(opt_t, heap) *file_options = NULL; + +/* Iterate FROM in reverse, writing option codes not yet in CODES into *TO. + Mark each new option code encountered in CODES. */ + +static void +reverse_iterate_options (VEC(opt_t, heap) *from, VEC(opt_t, heap) **to, + bitmap codes) +{ + int i; + + for (i = VEC_length (opt_t, from); i > 0; i--) + { + const opt_t *const o = VEC_index (opt_t, from, i - 1); + + if (bitmap_set_bit (codes, o->code)) + VEC_safe_push (opt_t, heap, *to, o); + } +} + +/* Concatenate options vectors FIRST and SECOND, rationalize so that only the + final of any given option remains, and return the result. */ + +static VEC(opt_t, heap) * +concatenate_options (VEC(opt_t, heap) *first, VEC(opt_t, heap) *second) +{ + VEC(opt_t, heap) *results = NULL; + bitmap codes = lto_bitmap_alloc (); + + reverse_iterate_options (second, &results, codes); + reverse_iterate_options (first, &results, codes); + + lto_bitmap_free (codes); + return results; +} + +/* Clear the options vector in *OPTS_P and set it to NULL. */ + +static void +clear_options (VEC(opt_t, heap) **opts_p) +{ + int i; + opt_t *o; + + for (i = 0; VEC_iterate (opt_t, *opts_p, i, o); i++) + free (o->arg); + + VEC_free (opt_t, heap, *opts_p); +} + +/* Write LENGTH bytes from ADDR to STREAM. */ + +static void +output_data_stream (struct lto_output_stream *stream, + const void *addr, size_t length) +{ + lto_output_data_stream (stream, addr, length); +} + +/* Write string STRING to STREAM. */ + +static void +output_string_stream (struct lto_output_stream *stream, const char *string) +{ + bool flag = false; + + if (string != NULL) + { + const size_t length = strlen (string); + + flag = true; + output_data_stream (stream, &flag, sizeof (flag)); + output_data_stream (stream, &length, sizeof (length)); + output_data_stream (stream, string, length); + } + else + output_data_stream (stream, &flag, sizeof (flag)); +} + +/* Read LENGTH bytes from STREAM to ADDR. */ + +static void +input_data_block (struct lto_input_block *ib, void *addr, size_t length) +{ + size_t i; + unsigned char *const buffer = (unsigned char *const) addr; + + for (i = 0; i < length; i++) + buffer[i] = lto_input_1_unsigned (ib); +} + +/* Return a string from IB. The string is allocated, and the caller is + responsible for freeing it. */ + +static char * +input_string_block (struct lto_input_block *ib) +{ + bool flag; + + input_data_block (ib, &flag, sizeof (flag)); + if (flag) + { + size_t length; + char *string; + + input_data_block (ib, &length, sizeof (length)); + string = (char *) xcalloc (1, length + 1); + input_data_block (ib, string, length); + + return string; + } + else + return NULL; +} + +/* Return true if this option is one we need to save in LTO output files. + At present, we pass along all target options, and common options that + involve position independent code. + + TODO This list of options requires expansion and rationalization. + Among others, optimization options may well be appropriate here. */ + +static bool +register_user_option_p (size_t code, int type) +{ + if (type == CL_TARGET) + return true; + else if (type == CL_COMMON) + { + return (code == OPT_fPIC + || code == OPT_fpic + || code == OPT_fPIE + || code == OPT_fpie + || code == OPT_fcommon + || code == OPT_fexceptions); + } + + return false; +} + +/* Note command line option with the given TYPE and CODE, ARG, and VALUE. + If relevant to LTO, save it in the user options vector. */ + +void +lto_register_user_option (size_t code, const char *arg, int value, int type) +{ + if (register_user_option_p (code, type)) + { + opt_t o; + + o.type = type; + o.code = code; + if (arg != NULL) + { + o.arg = (char *) xmalloc (strlen (arg) + 1); + strcpy (o.arg, arg); + } + else + o.arg = NULL; + o.value = value; + VEC_safe_push (opt_t, heap, user_options, &o); + } +} + +/* Empty the saved user options vector. */ + +void +lto_clear_user_options (void) +{ + clear_options (&user_options); +} + +/* Empty the saved file options vector. */ + +void +lto_clear_file_options (void) +{ + clear_options (&file_options); +} + +/* Concatenate the user options and any file options read from an LTO IL + file, and serialize them to STREAM. File options precede user options + so that the latter override the former when reissued. */ + +static void +output_options (struct lto_output_stream *stream) +{ + VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options); + const size_t length = VEC_length (opt_t, opts); + int i; + opt_t *o; + + output_data_stream (stream, &length, sizeof (length)); + + for (i = 0; VEC_iterate (opt_t, opts, i, o); i++) + { + output_data_stream (stream, &o->type, sizeof (o->type)); + output_data_stream (stream, &o->code, sizeof (o->code)); + output_string_stream (stream, o->arg); + output_data_stream (stream, &o->value, sizeof (o->value)); + } + + VEC_free (opt_t, heap, opts); +} + +/* Write currently held options to an LTO IL section. */ + +void +lto_write_options (void) +{ + char *const section_name = lto_get_section_name (LTO_section_opts, NULL); + struct lto_output_stream stream; + struct lto_simple_header header; + struct lto_output_stream *header_stream; + + lto_begin_section (section_name, !flag_wpa); + free (section_name); + + memset (&stream, 0, sizeof (stream)); + output_options (&stream); + + memset (&header, 0, sizeof (header)); + header.lto_header.major_version = LTO_major_version; + header.lto_header.minor_version = LTO_minor_version; + header.lto_header.section_type = LTO_section_opts; + + header.compressed_size = 0; + header.main_size = stream.total_size; + + header_stream = ((struct lto_output_stream *) + xcalloc (1, sizeof (*header_stream))); + lto_output_data_stream (header_stream, &header, sizeof (header)); + lto_write_stream (header_stream); + free (header_stream); + + lto_write_stream (&stream); + lto_end_section (); +} + +/* Unserialize an options vector from IB, and append to file_options. */ + +static void +input_options (struct lto_input_block *ib) +{ + size_t length, i; + + input_data_block (ib, &length, sizeof (length)); + + for (i = 0; i < length; i++) + { + opt_t o; + + input_data_block (ib, &o.type, sizeof (o.type)); + input_data_block (ib, &o.code, sizeof (o.code)); + o.arg = input_string_block (ib); + input_data_block (ib, &o.value, sizeof (o.value)); + VEC_safe_push (opt_t, heap, file_options, &o); + } +} + +/* Read options from an LTO IL section. */ + +void +lto_read_file_options (struct lto_file_decl_data *file_data) +{ + size_t len; + const char *data; + const struct lto_simple_header *header; + int32_t opts_offset; + struct lto_input_block ib; + + data = lto_get_section_data (file_data, LTO_section_opts, NULL, &len); + header = (const struct lto_simple_header *) data; + opts_offset = sizeof (*header); + + lto_check_version (header->lto_header.major_version, + header->lto_header.minor_version); + + LTO_INIT_INPUT_BLOCK (ib, data + opts_offset, 0, header->main_size); + input_options (&ib); + + lto_free_section_data (file_data, LTO_section_opts, 0, data, len); +} + +/* Concatenate the user options and any file options read from an LTO IL + file, and reissue them as if all had just been read in from the command + line. As with serialization, file options precede user options. */ + +void +lto_reissue_options (void) +{ + VEC(opt_t, heap) *opts = concatenate_options (file_options, user_options); + int i; + opt_t *o; + + for (i = 0; VEC_iterate (opt_t, opts, i, o); i++) + { + const struct cl_option *option = &cl_options[o->code]; + + if (option->flag_var) + set_option (option, o->value, o->arg); + + if (o->type == CL_TARGET) + targetm.handle_option (o->code, o->arg, o->value); + else if (o->type == CL_COMMON) + gcc_assert (option->flag_var); + else + gcc_unreachable (); + } + + VEC_free (opt_t, heap, opts); +} diff --git a/gcc/lto-section-in.c b/gcc/lto-section-in.c new file mode 100644 index 00000000000..da2384e0839 --- /dev/null +++ b/gcc/lto-section-in.c @@ -0,0 +1,489 @@ +/* Input functions for reading LTO sections. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Kenneth Zadeck + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "tree.h" +#include "expr.h" +#include "flags.h" +#include "params.h" +#include "input.h" +#include "varray.h" +#include "hashtab.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "cgraph.h" +#include "function.h" +#include "ggc.h" +#include "diagnostic.h" +#include "except.h" +#include "vec.h" +#include "timevar.h" +#include "output.h" +#include "lto-streamer.h" +#include "lto-compress.h" + +/* Section names. These must correspond to the values of + enum lto_section_type. */ +const char *lto_section_name[LTO_N_SECTION_TYPES] = +{ + "decls", + "function_body", + "static_initializer", + "cgraph", + "ipa_pure_const", + "ipa_reference", + "symtab", + "wpa_fixup", + "opts" +}; + +unsigned char +lto_input_1_unsigned (struct lto_input_block *ib) +{ + if (ib->p >= ib->len) + internal_error ("bytecode stream: trying to read %d bytes " + "after the end of the input buffer", ib->p - ib->len); + + return (ib->data[ib->p++]); +} + + +/* Read an ULEB128 Number of IB. */ + +unsigned HOST_WIDE_INT +lto_input_uleb128 (struct lto_input_block *ib) +{ + unsigned HOST_WIDE_INT result = 0; + int shift = 0; + unsigned HOST_WIDE_INT byte; + + while (true) + { + byte = lto_input_1_unsigned (ib); + result |= (byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + return result; + } +} + +/* HOST_WIDEST_INT version of lto_input_uleb128. IB is as in + lto_input_uleb128. */ + +unsigned HOST_WIDEST_INT +lto_input_widest_uint_uleb128 (struct lto_input_block *ib) +{ + unsigned HOST_WIDEST_INT result = 0; + int shift = 0; + unsigned HOST_WIDEST_INT byte; + + while (true) + { + byte = lto_input_1_unsigned (ib); + result |= (byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + return result; + } +} + +/* Read an SLEB128 Number of IB. */ + +HOST_WIDE_INT +lto_input_sleb128 (struct lto_input_block *ib) +{ + HOST_WIDE_INT result = 0; + int shift = 0; + unsigned HOST_WIDE_INT byte; + + while (true) + { + byte = lto_input_1_unsigned (ib); + result |= (byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + { + if ((shift < HOST_BITS_PER_WIDE_INT) && (byte & 0x40)) + result |= - ((HOST_WIDE_INT)1 << shift); + + return result; + } + } +} + + +/* Hooks so that the ipa passes can call into the lto front end to get + sections. */ + +static struct lto_file_decl_data ** file_decl_data; +static lto_get_section_data_f* get_section_f; +static lto_free_section_data_f* free_section_f; + + +/* This is called from the lto front end to set up the hooks that are + used by the ipa passes to get the data that they will + deserialize. */ + +void +lto_set_in_hooks (struct lto_file_decl_data ** data, + lto_get_section_data_f* get_f, + lto_free_section_data_f* free_f) +{ + file_decl_data = data; + get_section_f = get_f; + free_section_f = free_f; +} + + +/* Return an array of file decl datas for all of the files passed to + this compilation. */ + +struct lto_file_decl_data ** +lto_get_file_decl_data (void) +{ + gcc_assert (file_decl_data); + return file_decl_data; +} + +/* Buffer structure for accumulating data from compression callbacks. */ + +struct lto_buffer +{ + char *data; + size_t length; +}; + +/* Compression callback, append LENGTH bytes from DATA to the buffer pointed + to by OPAQUE. */ + +static void +lto_append_data (const char *data, unsigned length, void *opaque) +{ + struct lto_buffer *buffer = (struct lto_buffer *) opaque; + + buffer->data = (char *) xrealloc (buffer->data, buffer->length + length); + memcpy (buffer->data + buffer->length, data, length); + buffer->length += length; +} + +/* Header placed in returned uncompressed data streams. Allows the + uncompressed allocated data to be mapped back to the underlying + compressed data for use with free_section_f. */ + +struct lto_data_header +{ + const char *data; + size_t len; +}; + +/* Return a char pointer to the start of a data stream for an LTO pass + or function. FILE_DATA indicates where to obtain the data. + SECTION_TYPE is the type of information to be obtained. NAME is + the name of the function and is only used when finding a function + body; otherwise it is NULL. LEN is the size of the data + returned. */ + +const char * +lto_get_section_data (struct lto_file_decl_data *file_data, + enum lto_section_type section_type, + const char *name, + size_t *len) +{ + const char *data = (get_section_f) (file_data, section_type, name, len); + const size_t header_length = sizeof (struct lto_data_header); + struct lto_data_header *header; + struct lto_buffer buffer; + struct lto_compression_stream *stream; + lto_stats.section_size[section_type] += *len; + + if (data == NULL) + return NULL; + + /* FIXME lto: WPA mode does not write compressed sections, so for now + suppress uncompression if flag_ltrans. */ + if (flag_ltrans) + return data; + + /* Create a mapping header containing the underlying data and length, + and prepend this to the uncompression buffer. The uncompressed data + then follows, and a pointer to the start of the uncompressed data is + returned. */ + header = (struct lto_data_header *) xmalloc (header_length); + header->data = data; + header->len = *len; + + buffer.data = (char *) header; + buffer.length = header_length; + + stream = lto_start_uncompression (lto_append_data, &buffer); + lto_uncompress_block (stream, data, *len); + lto_end_uncompression (stream); + + *len = buffer.length - header_length; + return buffer.data + header_length; +} + + +/* Free the data found from the above call. The first three + parameters are the same as above. DATA is the data to be freed and + LEN is the length of that data. */ + +void +lto_free_section_data (struct lto_file_decl_data *file_data, + enum lto_section_type section_type, + const char *name, + const char *data, + size_t len) +{ + const size_t header_length = sizeof (struct lto_data_header); + const char *real_data = data - header_length; + const struct lto_data_header *header + = (const struct lto_data_header *) real_data; + + gcc_assert (free_section_f); + + /* FIXME lto: WPA mode does not write compressed sections, so for now + suppress uncompression mapping if flag_ltrans. */ + if (flag_ltrans) + { + (free_section_f) (file_data, section_type, name, data, len); + return; + } + + /* The underlying data address has been extracted from the mapping header. + Free that, then free the allocated uncompression buffer. */ + (free_section_f) (file_data, section_type, name, header->data, header->len); + free (CONST_CAST (char *, real_data)); +} + + +/* Load a section of type SECTION_TYPE from FILE_DATA, parse the + header and then return an input block pointing to the section. The + raw pointer to the section is returned in DATAR and LEN. These are + used to free the section. Return NULL if the section is not present. */ + +struct lto_input_block * +lto_create_simple_input_block (struct lto_file_decl_data *file_data, + enum lto_section_type section_type, + const char **datar, size_t *len) +{ + const char *data = lto_get_section_data (file_data, section_type, NULL, len); + const struct lto_simple_header * header + = (const struct lto_simple_header *) data; + + struct lto_input_block* ib_main; + int32_t main_offset = sizeof (struct lto_simple_header); + + if (!data) + return NULL; + + ib_main = XNEW (struct lto_input_block); + + *datar = data; + LTO_INIT_INPUT_BLOCK_PTR (ib_main, data + main_offset, + 0, header->main_size); + + return ib_main; +} + + +/* Close the section returned from a call to + LTO_CREATE_SIMPLE_INPUT_BLOCK. IB is the input block returned from + that call. The FILE_DATA and SECTION_TYPE are the same as what was + passed to that call and the DATA and LEN are what was returned from + that call. */ + +void +lto_destroy_simple_input_block (struct lto_file_decl_data *file_data, + enum lto_section_type section_type, + struct lto_input_block *ib, + const char *data, size_t len) +{ + free (ib); + lto_free_section_data (file_data, section_type, NULL, data, len); +} + +/*****************************************************************************/ +/* Record renamings of static declarations */ +/*****************************************************************************/ + +struct lto_renaming_slot +{ + const char *old_name; + const char *new_name; +}; + +/* Returns a hash code for P. */ + +static hashval_t +hash_name (const void *p) +{ + const struct lto_renaming_slot *ds = (const struct lto_renaming_slot *) p; + return (hashval_t) htab_hash_string (ds->new_name); +} + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +eq_name (const void *p1, const void *p2) +{ + const struct lto_renaming_slot *s1 = + (const struct lto_renaming_slot *) p1; + const struct lto_renaming_slot *s2 = + (const struct lto_renaming_slot *) p2; + + return strcmp (s1->new_name, s2->new_name) == 0; +} + +/* Free a renaming table entry. */ + +static void +renaming_slot_free (void *slot) +{ + struct lto_renaming_slot *s = (struct lto_renaming_slot *) slot; + + free (CONST_CAST (void *, (const void *) s->old_name)); + free (CONST_CAST (void *, (const void *) s->new_name)); + free ((void *) s); +} + +/* Create an empty hash table for recording declaration renamings. */ + +htab_t +lto_create_renaming_table (void) +{ + return htab_create (37, hash_name, eq_name, renaming_slot_free); +} + +/* Record a declaration name mapping OLD_NAME -> NEW_NAME. DECL_DATA + holds the renaming hash table to use. */ + +void +lto_record_renamed_decl (struct lto_file_decl_data *decl_data, + const char *old_name, const char *new_name) +{ + void **slot; + struct lto_renaming_slot r_slot; + + r_slot.new_name = new_name; + slot = htab_find_slot (decl_data->renaming_hash_table, &r_slot, INSERT); + if (*slot == NULL) + { + struct lto_renaming_slot *new_slot = XNEW (struct lto_renaming_slot); + new_slot->old_name = xstrdup (old_name); + new_slot->new_name = xstrdup (new_name); + *slot = new_slot; + } + else + gcc_unreachable (); +} + + +/* Given a string NAME, return the string that it has been mapped to + by lto_record_renamed_decl. If NAME was not renamed, it is + returned unchanged. DECL_DATA holds the renaming hash table to use. */ + +const char * +lto_get_decl_name_mapping (struct lto_file_decl_data *decl_data, + const char *name) +{ + htab_t renaming_hash_table = decl_data->renaming_hash_table; + struct lto_renaming_slot *slot; + struct lto_renaming_slot r_slot; + + r_slot.new_name = name; + slot = (struct lto_renaming_slot *) htab_find (renaming_hash_table, &r_slot); + if (slot) + return slot->old_name; + else + return name; +} + +/*****************************************************************************/ +/* Input decl state object. */ +/*****************************************************************************/ + +/* Return a newly created in-decl state object. */ + +struct lto_in_decl_state * +lto_new_in_decl_state (void) +{ + struct lto_in_decl_state *state; + + state = ((struct lto_in_decl_state *) xmalloc (sizeof (*state))); + memset (state, 0, sizeof (*state)); + return state; +} + +/* Delete STATE and its components. */ + +void +lto_delete_in_decl_state (struct lto_in_decl_state *state) +{ + int i; + + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + if (state->streams[i].trees) + free (state->streams[i].trees); + free (state); +} + +/* Hashtable helpers. lto_in_decl_states are hash by their function decls. */ + +hashval_t +lto_hash_in_decl_state (const void *p) +{ + const struct lto_in_decl_state *state = (const struct lto_in_decl_state *) p; + return htab_hash_pointer (state->fn_decl); +} + +/* Return true if the fn_decl field of the lto_in_decl_state pointed to by + P1 equals to the function decl P2. */ + +int +lto_eq_in_decl_state (const void *p1, const void *p2) +{ + const struct lto_in_decl_state *state1 = + (const struct lto_in_decl_state *) p1; + const struct lto_in_decl_state *state2 = + (const struct lto_in_decl_state *) p2; + return state1->fn_decl == state2->fn_decl; +} + + +/* Search the in-decl state of a function FUNC contained in the file + associated with FILE_DATA. Return NULL if not found. */ + +struct lto_in_decl_state* +lto_get_function_in_decl_state (struct lto_file_decl_data *file_data, + tree func) +{ + struct lto_in_decl_state temp; + void **slot; + + temp.fn_decl = func; + slot = htab_find_slot (file_data->function_decl_states, &temp, NO_INSERT); + return slot? ((struct lto_in_decl_state*) *slot) : NULL; +} diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c new file mode 100644 index 00000000000..e347027c709 --- /dev/null +++ b/gcc/lto-section-out.c @@ -0,0 +1,652 @@ +/* Functions for writing LTO sections. + + Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Kenneth Zadeck + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "tree.h" +#include "expr.h" +#include "params.h" +#include "input.h" +#include "varray.h" +#include "hashtab.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "function.h" +#include "ggc.h" +#include "except.h" +#include "vec.h" +#include "pointer-set.h" +#include "bitmap.h" +#include "langhooks.h" +#include "lto-streamer.h" +#include "lto-compress.h" + +static VEC(lto_out_decl_state_ptr, heap) *decl_state_stack; + +/* List of out decl states used by functions. We use this to + generate the decl directory later. */ + +VEC(lto_out_decl_state_ptr, heap) *lto_function_decl_states; + +/* Bitmap indexed by DECL_UID to indicate if a function needs to be + forced extern inline. */ +static bitmap forced_extern_inline; + +/* Initialize states for determining which function decls to be ouput + as extern inline, regardless of the decls' own attributes. */ + +void +lto_new_extern_inline_states (void) +{ + forced_extern_inline = lto_bitmap_alloc (); +} + +/* Releasing resources use for states to determine which function decls + to be ouput as extern inline */ + +void +lto_delete_extern_inline_states (void) +{ + lto_bitmap_free (forced_extern_inline); + forced_extern_inline = NULL; +} + +/* Force all the functions in DECLS to be output as extern inline. + DECLS is a bitmap indexed by DECL_UID. */ + +void +lto_force_functions_extern_inline (bitmap decls) +{ + bitmap_ior_into (forced_extern_inline, decls); +} + +/* Return true if FN_DECL is a function which should be emitted as + extern inline. */ + +bool +lto_forced_extern_inline_p (tree fn_decl) +{ + return bitmap_bit_p (forced_extern_inline, DECL_UID (fn_decl)); +} + +/* Returns a hash code for P. */ + +hashval_t +lto_hash_decl_slot_node (const void *p) +{ + const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p; + + /* + return (hashval_t) DECL_UID (ds->t); + */ + return (hashval_t) TREE_HASH (ds->t); +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +int +lto_eq_decl_slot_node (const void *p1, const void *p2) +{ + const struct lto_decl_slot *ds1 = + (const struct lto_decl_slot *) p1; + const struct lto_decl_slot *ds2 = + (const struct lto_decl_slot *) p2; + + /* + return DECL_UID (ds1->t) == DECL_UID (ds2->t); + */ + return ds1->t == ds2->t; +} + + +/* Returns a hash code for P. */ + +hashval_t +lto_hash_type_slot_node (const void *p) +{ + const struct lto_decl_slot *ds = (const struct lto_decl_slot *) p; + return (hashval_t) TYPE_UID (ds->t); +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +int +lto_eq_type_slot_node (const void *p1, const void *p2) +{ + const struct lto_decl_slot *ds1 = + (const struct lto_decl_slot *) p1; + const struct lto_decl_slot *ds2 = + (const struct lto_decl_slot *) p2; + + return TYPE_UID (ds1->t) == TYPE_UID (ds2->t); +} + +/***************************************************************************** + Output routines shared by all of the serialization passes. +*****************************************************************************/ + + +/* Flush compressed stream data function, sends NUM_CHARS from CHARS + to the append lang hook, OPAQUE is currently always NULL. */ + +static void +lto_append_data (const char *chars, unsigned int num_chars, void *opaque) +{ + gcc_assert (opaque == NULL); + lang_hooks.lto.append_data (chars, num_chars, opaque); +} + +/* Pointer to the current compression stream. */ + +static struct lto_compression_stream *compression_stream = NULL; + +/* Begin a new output section named NAME. If COMPRESS is true, zlib compress + the section. */ + +void +lto_begin_section (const char *name, bool compress) +{ + lang_hooks.lto.begin_section (name); + + /* FIXME lto: for now, suppress compression if the lang_hook that appends + data is anything other than assembler output. The effect here is that + we get compression of IL only in non-ltrans object files. */ + gcc_assert (compression_stream == NULL); + if (compress) + compression_stream = lto_start_compression (lto_append_data, NULL); +} + + +/* End the current output section. */ + +void +lto_end_section (void) +{ + if (compression_stream) + { + lto_end_compression (compression_stream); + compression_stream = NULL; + } + lang_hooks.lto.end_section (); +} + + +/* Write all of the chars in OBS to the assembler. Recycle the blocks + in obs as this is being done. */ + +void +lto_write_stream (struct lto_output_stream *obs) +{ + unsigned int block_size = 1024; + struct lto_char_ptr_base *block; + struct lto_char_ptr_base *next_block; + if (!obs->first_block) + return; + + for (block = obs->first_block; block; block = next_block) + { + const char *base = ((char *)block) + sizeof (struct lto_char_ptr_base); + unsigned int num_chars = block_size - sizeof (struct lto_char_ptr_base); + + /* If this is not the last block, it is full. If it is the last + block, left_in_block indicates how many chars are unoccupied in + this block; subtract from num_chars to obtain occupancy. */ + next_block = (struct lto_char_ptr_base *) block->ptr; + if (!next_block) + num_chars -= obs->left_in_block; + + /* FIXME lto: WPA mode uses an ELF function as a lang_hook to append + output data. This hook is not happy with the way that compression + blocks up output differently to the way it's blocked here. So for + now, we don't compress WPA output. */ + if (compression_stream) + { + lto_compress_block (compression_stream, base, num_chars); + lang_hooks.lto.append_data (NULL, 0, block); + } + else + lang_hooks.lto.append_data (base, num_chars, block); + block_size *= 2; + } +} + + +/* Adds a new block to output stream OBS. */ + +static void +append_block (struct lto_output_stream *obs) +{ + struct lto_char_ptr_base *new_block; + + gcc_assert (obs->left_in_block == 0); + + if (obs->first_block == NULL) + { + /* This is the first time the stream has been written + into. */ + obs->block_size = 1024; + new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); + obs->first_block = new_block; + } + else + { + struct lto_char_ptr_base *tptr; + /* Get a new block that is twice as big as the last block + and link it into the list. */ + obs->block_size *= 2; + new_block = (struct lto_char_ptr_base*) xmalloc (obs->block_size); + /* The first bytes of the block are reserved as a pointer to + the next block. Set the chain of the full block to the + pointer to the new block. */ + tptr = obs->current_block; + tptr->ptr = (char *) new_block; + } + + /* Set the place for the next char at the first position after the + chain to the next block. */ + obs->current_pointer + = ((char *) new_block) + sizeof (struct lto_char_ptr_base); + obs->current_block = new_block; + /* Null out the newly allocated block's pointer to the next block. */ + new_block->ptr = NULL; + obs->left_in_block = obs->block_size - sizeof (struct lto_char_ptr_base); +} + + +/* Write a character to the output block. */ + +void +lto_output_1_stream (struct lto_output_stream *obs, char c) +{ + /* No space left. */ + if (obs->left_in_block == 0) + append_block (obs); + + /* Write the actual character. */ + *obs->current_pointer = c; + obs->current_pointer++; + obs->total_size++; + obs->left_in_block--; +} + + +/* Write raw DATA of length LEN to the output block OB. */ + +void +lto_output_data_stream (struct lto_output_stream *obs, const void *data, + size_t len) +{ + while (len) + { + size_t copy; + + /* No space left. */ + if (obs->left_in_block == 0) + append_block (obs); + + /* Determine how many bytes to copy in this loop. */ + if (len <= obs->left_in_block) + copy = len; + else + copy = obs->left_in_block; + + /* Copy the data and do bookkeeping. */ + memcpy (obs->current_pointer, data, copy); + obs->current_pointer += copy; + obs->total_size += copy; + obs->left_in_block -= copy; + data = (const char *) data + copy; + len -= copy; + } +} + + +/* Output an unsigned LEB128 quantity to OBS. */ + +void +lto_output_uleb128_stream (struct lto_output_stream *obs, + unsigned HOST_WIDE_INT work) +{ + do + { + unsigned int byte = (work & 0x7f); + work >>= 7; + if (work != 0) + /* More bytes to follow. */ + byte |= 0x80; + + lto_output_1_stream (obs, byte); + } + while (work != 0); +} + +/* Identical to output_uleb128_stream above except using unsigned + HOST_WIDEST_INT type. For efficiency on host where unsigned HOST_WIDEST_INT + is not native, we only use this if we know that HOST_WIDE_INT is not wide + enough. */ + +void +lto_output_widest_uint_uleb128_stream (struct lto_output_stream *obs, + unsigned HOST_WIDEST_INT work) +{ + do + { + unsigned int byte = (work & 0x7f); + work >>= 7; + if (work != 0) + /* More bytes to follow. */ + byte |= 0x80; + + lto_output_1_stream (obs, byte); + } + while (work != 0); +} + + +/* Output a signed LEB128 quantity. */ + +void +lto_output_sleb128_stream (struct lto_output_stream *obs, HOST_WIDE_INT work) +{ + int more, byte; + + do + { + byte = (work & 0x7f); + /* arithmetic shift */ + work >>= 7; + more = !((work == 0 && (byte & 0x40) == 0) + || (work == -1 && (byte & 0x40) != 0)); + if (more) + byte |= 0x80; + + lto_output_1_stream (obs, byte); + } + while (more); +} + + +/* Lookup NAME in ENCODER. If NAME is not found, create a new entry in + ENCODER for NAME with the next available index of ENCODER, then + print the index to OBS. True is returned if NAME was added to + ENCODER. The resulting index is stored in THIS_INDEX. + + If OBS is NULL, the only action is to add NAME to the encoder. */ + +bool +lto_output_decl_index (struct lto_output_stream *obs, + struct lto_tree_ref_encoder *encoder, + tree name, unsigned int *this_index) +{ + void **slot; + struct lto_decl_slot d_slot; + int index; + bool new_entry_p = FALSE; + + d_slot.t = name; + slot = htab_find_slot (encoder->tree_hash_table, &d_slot, INSERT); + if (*slot == NULL) + { + struct lto_decl_slot *new_slot + = (struct lto_decl_slot *) xmalloc (sizeof (struct lto_decl_slot)); + index = encoder->next_index++; + + new_slot->t = name; + new_slot->slot_num = index; + *slot = new_slot; + VEC_safe_push (tree, heap, encoder->trees, name); + new_entry_p = TRUE; + } + else + { + struct lto_decl_slot *old_slot = (struct lto_decl_slot *)*slot; + index = old_slot->slot_num; + } + + if (obs) + lto_output_uleb128_stream (obs, index); + *this_index = index; + return new_entry_p; +} + +/* Output a field DECL to OBS. */ + +void +lto_output_field_decl_index (struct lto_out_decl_state *decl_state, + struct lto_output_stream * obs, tree decl) +{ + unsigned int index; + lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FIELD_DECL], + decl, &index); +} + +/* Output a function DECL to OBS. */ + +void +lto_output_fn_decl_index (struct lto_out_decl_state *decl_state, + struct lto_output_stream * obs, tree decl) +{ + unsigned int index; + lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_FN_DECL], + decl, &index); +} + +/* Output a namespace DECL to OBS. */ + +void +lto_output_namespace_decl_index (struct lto_out_decl_state *decl_state, + struct lto_output_stream * obs, tree decl) +{ + unsigned int index; + lto_output_decl_index (obs, + &decl_state->streams[LTO_DECL_STREAM_NAMESPACE_DECL], + decl, &index); +} + +/* Output a static or extern var DECL to OBS. */ + +void +lto_output_var_decl_index (struct lto_out_decl_state *decl_state, + struct lto_output_stream * obs, tree decl) +{ + unsigned int index; + lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_VAR_DECL], + decl, &index); +} + +/* Output a type DECL to OBS. */ + +void +lto_output_type_decl_index (struct lto_out_decl_state *decl_state, + struct lto_output_stream * obs, tree decl) +{ + unsigned int index; + lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE_DECL], + decl, &index); +} + +/* Output a type REF to OBS. */ + +void +lto_output_type_ref_index (struct lto_out_decl_state *decl_state, + struct lto_output_stream *obs, tree ref) +{ + unsigned int index; + lto_output_decl_index (obs, &decl_state->streams[LTO_DECL_STREAM_TYPE], + ref, &index); +} + + +/* Create the output block and return it. */ + +struct lto_simple_output_block * +lto_create_simple_output_block (enum lto_section_type section_type) +{ + struct lto_simple_output_block *ob + = ((struct lto_simple_output_block *) + xcalloc (1, sizeof (struct lto_simple_output_block))); + + ob->section_type = section_type; + ob->decl_state = lto_get_out_decl_state (); + ob->main_stream = ((struct lto_output_stream *) + xcalloc (1, sizeof (struct lto_output_stream))); + + return ob; +} + + +/* Produce a simple section for one of the ipa passes. */ + +void +lto_destroy_simple_output_block (struct lto_simple_output_block *ob) +{ + char *section_name; + struct lto_simple_header header; + struct lto_output_stream *header_stream; + + section_name = lto_get_section_name (ob->section_type, NULL); + lto_begin_section (section_name, !flag_wpa); + free (section_name); + + /* Write the header which says how to decode the pieces of the + t. */ + memset (&header, 0, sizeof (struct lto_simple_header)); + header.lto_header.major_version = LTO_major_version; + header.lto_header.minor_version = LTO_minor_version; + header.lto_header.section_type = LTO_section_cgraph; + + header.compressed_size = 0; + + header.main_size = ob->main_stream->total_size; + + header_stream = XCNEW (struct lto_output_stream); + lto_output_data_stream (header_stream, &header, sizeof header); + lto_write_stream (header_stream); + free (header_stream); + + lto_write_stream (ob->main_stream); + + /* Put back the assembly section that was there before we started + writing lto info. */ + lto_end_section (); + + free (ob->main_stream); + free (ob); +} + + +/* Return a new lto_out_decl_state. */ + +struct lto_out_decl_state * +lto_new_out_decl_state (void) +{ + struct lto_out_decl_state *state = XCNEW (struct lto_out_decl_state); + int i; + htab_hash hash_fn; + htab_eq eq_fn; + + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + { + if (i == LTO_DECL_STREAM_TYPE) + { + hash_fn = lto_hash_type_slot_node; + eq_fn = lto_eq_type_slot_node; + } + else + { + hash_fn = lto_hash_decl_slot_node; + eq_fn = lto_eq_decl_slot_node; + } + lto_init_tree_ref_encoder (&state->streams[i], hash_fn, eq_fn); + } + + state->cgraph_node_encoder = lto_cgraph_encoder_new (); + + return state; +} + + +/* Delete STATE and components. */ + +void +lto_delete_out_decl_state (struct lto_out_decl_state *state) +{ + int i; + + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + lto_destroy_tree_ref_encoder (&state->streams[i]); + + free (state); +} + + +/* Get the currently used lto_out_decl_state structure. */ + +struct lto_out_decl_state * +lto_get_out_decl_state (void) +{ + return VEC_last (lto_out_decl_state_ptr, decl_state_stack); +} + +/* Push STATE to top of out decl stack. */ + +void +lto_push_out_decl_state (struct lto_out_decl_state *state) +{ + VEC_safe_push (lto_out_decl_state_ptr, heap, decl_state_stack, state); +} + +/* Pop the currently used out-decl state from top of stack. */ + +struct lto_out_decl_state * +lto_pop_out_decl_state (void) +{ + return VEC_pop (lto_out_decl_state_ptr, decl_state_stack); +} + +/* Record STATE after it has been used in serializing the body of + FN_DECL. STATE should no longer be used by the caller. The ownership + of it is taken over from this point. */ + +void +lto_record_function_out_decl_state (tree fn_decl, + struct lto_out_decl_state *state) +{ + int i; + + /* Strip all hash tables to save some memory. */ + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + if (state->streams[i].tree_hash_table) + { + htab_delete (state->streams[i].tree_hash_table); + state->streams[i].tree_hash_table = NULL; + } + state->fn_decl = fn_decl; + VEC_safe_push (lto_out_decl_state_ptr, heap, lto_function_decl_states, + state); +} diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c new file mode 100644 index 00000000000..f7c793647bc --- /dev/null +++ b/gcc/lto-streamer-in.c @@ -0,0 +1,2741 @@ +/* Read the GIMPLE representation from a file stream. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Kenneth Zadeck + Re-implemented 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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "tree.h" +#include "expr.h" +#include "flags.h" +#include "params.h" +#include "input.h" +#include "varray.h" +#include "hashtab.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "function.h" +#include "ggc.h" +#include "diagnostic.h" +#include "libfuncs.h" +#include "except.h" +#include "debug.h" +#include "vec.h" +#include "timevar.h" +#include "output.h" +#include "ipa-utils.h" +#include "lto-streamer.h" +#include "tree-pass.h" + +/* Data structure used to hash file names in the source_location field. */ +struct string_slot +{ + const char *s; + unsigned int slot_num; +}; + +/* The table to hold the file names. */ +static htab_t file_name_hash_table; + + +/* Check that tag ACTUAL has one of the given values. NUM_TAGS is the + number of valid tag values to check. */ + +static void +lto_tag_check_set (enum LTO_tags actual, int ntags, ...) +{ + va_list ap; + int i; + + va_start (ap, ntags); + for (i = 0; i < ntags; i++) + if ((unsigned) actual == va_arg (ap, unsigned)) + { + va_end (ap); + return; + } + + va_end (ap); + internal_error ("bytecode stream: unexpected tag %s", lto_tag_name (actual)); +} + + +/* Check that tag ACTUAL is in the range [TAG1, TAG2]. */ + +static void +lto_tag_check_range (enum LTO_tags actual, enum LTO_tags tag1, + enum LTO_tags tag2) +{ + if (actual < tag1 || actual > tag2) + internal_error ("bytecode stream: tag %s is not in the expected range " + "[%s, %s]", + lto_tag_name (actual), + lto_tag_name (tag1), + lto_tag_name (tag2)); +} + + +/* Check that tag ACTUAL == EXPECTED. */ + +static void +lto_tag_check (enum LTO_tags actual, enum LTO_tags expected) +{ + if (actual != expected) + internal_error ("bytecode stream: expected tag %s instead of %s", + lto_tag_name (expected), lto_tag_name (actual)); +} + + +/* Return a hash code for P. */ + +static hashval_t +hash_string_slot_node (const void *p) +{ + const struct string_slot *ds = (const struct string_slot *) p; + return (hashval_t) htab_hash_string (ds->s); +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +eq_string_slot_node (const void *p1, const void *p2) +{ + const struct string_slot *ds1 = (const struct string_slot *) p1; + const struct string_slot *ds2 = (const struct string_slot *) p2; + return strcmp (ds1->s, ds2->s) == 0; +} + + +/* Read a string from the string table in DATA_IN using input block + IB. Write the length to RLEN. */ + +static const char * +input_string_internal (struct data_in *data_in, struct lto_input_block *ib, + unsigned int *rlen) +{ + struct lto_input_block str_tab; + unsigned int len; + unsigned int loc; + const char *result; + + loc = lto_input_uleb128 (ib); + LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc, data_in->strings_len); + len = lto_input_uleb128 (&str_tab); + *rlen = len; + + if (str_tab.p + len > data_in->strings_len) + internal_error ("bytecode stream: string too long for the string table"); + + result = (const char *)(data_in->strings + str_tab.p); + + return result; +} + + +/* Read a STRING_CST from the string table in DATA_IN using input + block IB. */ + +static tree +input_string_cst (struct data_in *data_in, struct lto_input_block *ib) +{ + unsigned int len; + const char * ptr; + unsigned int is_null; + + is_null = lto_input_uleb128 (ib); + if (is_null) + return NULL; + + ptr = input_string_internal (data_in, ib, &len); + return build_string (len, ptr); +} + + +/* Read an IDENTIFIER from the string table in DATA_IN using input + block IB. */ + +static tree +input_identifier (struct data_in *data_in, struct lto_input_block *ib) +{ + unsigned int len; + const char *ptr; + unsigned int is_null; + + is_null = lto_input_uleb128 (ib); + if (is_null) + return NULL; + + ptr = input_string_internal (data_in, ib, &len); + return get_identifier_with_length (ptr, len); +} + +/* Read a NULL terminated string from the string table in DATA_IN. */ + +static const char * +input_string (struct data_in *data_in, struct lto_input_block *ib) +{ + unsigned int len; + const char *ptr; + unsigned int is_null; + + is_null = lto_input_uleb128 (ib); + if (is_null) + return NULL; + + ptr = input_string_internal (data_in, ib, &len); + if (ptr[len - 1] != '\0') + internal_error ("bytecode stream: found non-null terminated string"); + + return ptr; +} + + +/* Return the next tag in the input block IB. */ + +static enum LTO_tags +input_record_start (struct lto_input_block *ib) +{ + enum LTO_tags tag = (enum LTO_tags) lto_input_uleb128 (ib); + return tag; +} + + +/* Lookup STRING in file_name_hash_table. If found, return the existing + string, otherwise insert STRING as the canonical version. */ + +static const char * +canon_file_name (const char *string) +{ + void **slot; + struct string_slot s_slot; + s_slot.s = string; + + slot = htab_find_slot (file_name_hash_table, &s_slot, INSERT); + if (*slot == NULL) + { + size_t len; + char *saved_string; + struct string_slot *new_slot; + + len = strlen (string); + saved_string = (char *) xmalloc (len + 1); + new_slot = XCNEW (struct string_slot); + strcpy (saved_string, string); + new_slot->s = saved_string; + *slot = new_slot; + return saved_string; + } + else + { + struct string_slot *old_slot = (struct string_slot *) *slot; + return old_slot->s; + } +} + + +/* Clear the line info stored in DATA_IN. */ + +static void +clear_line_info (struct data_in *data_in) +{ + if (data_in->current_file) + linemap_add (line_table, LC_LEAVE, false, NULL, 0); + data_in->current_file = NULL; + data_in->current_line = 0; + data_in->current_col = 0; +} + + +/* Read a location from input block IB. */ + +static location_t +lto_input_location (struct lto_input_block *ib, struct data_in *data_in) +{ + expanded_location xloc; + + xloc.file = input_string (data_in, ib); + if (xloc.file == NULL) + return UNKNOWN_LOCATION; + + xloc.file = canon_file_name (xloc.file); + xloc.line = lto_input_sleb128 (ib); + xloc.column = lto_input_sleb128 (ib); + xloc.sysp = lto_input_sleb128 (ib); + + if (data_in->current_file != xloc.file) + { + if (data_in->current_file) + linemap_add (line_table, LC_LEAVE, false, NULL, 0); + + linemap_add (line_table, LC_ENTER, xloc.sysp, xloc.file, xloc.line); + } + else if (data_in->current_line != xloc.line) + linemap_line_start (line_table, xloc.line, xloc.column); + + data_in->current_file = xloc.file; + data_in->current_line = xloc.line; + data_in->current_col = xloc.column; + + return linemap_position_for_column (line_table, xloc.column); +} + + +/* Read a reference to a tree node from DATA_IN using input block IB. + TAG is the expected node that should be found in IB, if TAG belongs + to one of the indexable trees, expect to read a reference index to + be looked up in one of the symbol tables, otherwise read the pysical + representation of the tree using lto_input_tree. FN is the + function scope for the read tree. */ + +static tree +lto_input_tree_ref (struct lto_input_block *ib, struct data_in *data_in, + struct function *fn, enum LTO_tags tag) +{ + unsigned HOST_WIDE_INT ix_u; + tree result = NULL_TREE; + + lto_tag_check_range (tag, LTO_field_decl_ref, LTO_global_decl_ref); + + switch (tag) + { + case LTO_type_ref: + ix_u = lto_input_uleb128 (ib); + result = lto_file_decl_data_get_type (data_in->file_data, ix_u); + break; + + case LTO_ssa_name_ref: + ix_u = lto_input_uleb128 (ib); + result = VEC_index (tree, SSANAMES (fn), ix_u); + break; + + case LTO_field_decl_ref: + ix_u = lto_input_uleb128 (ib); + result = lto_file_decl_data_get_field_decl (data_in->file_data, ix_u); + break; + + case LTO_function_decl_ref: + ix_u = lto_input_uleb128 (ib); + result = lto_file_decl_data_get_fn_decl (data_in->file_data, ix_u); + break; + + case LTO_type_decl_ref: + ix_u = lto_input_uleb128 (ib); + result = lto_file_decl_data_get_type_decl (data_in->file_data, ix_u); + break; + + case LTO_namespace_decl_ref: + ix_u = lto_input_uleb128 (ib); + result = lto_file_decl_data_get_namespace_decl (data_in->file_data, ix_u); + break; + + case LTO_global_decl_ref: + case LTO_result_decl_ref: + case LTO_const_decl_ref: + case LTO_imported_decl_ref: + case LTO_label_decl_ref: + ix_u = lto_input_uleb128 (ib); + result = lto_file_decl_data_get_var_decl (data_in->file_data, ix_u); + if (tag == LTO_global_decl_ref) + varpool_mark_needed_node (varpool_node (result)); + break; + + default: + gcc_unreachable (); + } + + gcc_assert (result); + + return result; +} + + +/* Read and return a double-linked list of catch handlers from input + block IB, using descriptors in DATA_IN. */ + +static struct eh_catch_d * +lto_input_eh_catch_list (struct lto_input_block *ib, struct data_in *data_in, + eh_catch *last_p) +{ + eh_catch first; + enum LTO_tags tag; + + *last_p = first = NULL; + tag = input_record_start (ib); + while (tag) + { + tree list; + eh_catch n; + + lto_tag_check_range (tag, LTO_eh_catch, LTO_eh_catch); + + /* Read the catch node. */ + n = GGC_CNEW (struct eh_catch_d); + n->type_list = lto_input_tree (ib, data_in); + n->filter_list = lto_input_tree (ib, data_in); + n->label = lto_input_tree (ib, data_in); + + /* Register all the types in N->FILTER_LIST. */ + for (list = n->filter_list; list; list = TREE_CHAIN (list)) + add_type_for_runtime (TREE_VALUE (list)); + + /* Chain N to the end of the list. */ + if (*last_p) + (*last_p)->next_catch = n; + n->prev_catch = *last_p; + *last_p = n; + + /* Set the head of the list the first time through the loop. */ + if (first == NULL) + first = n; + + tag = input_record_start (ib); + } + + return first; +} + + +/* Read and return EH region IX from input block IB, using descriptors + in DATA_IN. */ + +static eh_region +input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix) +{ + enum LTO_tags tag; + eh_region r; + + /* Read the region header. */ + tag = input_record_start (ib); + if (tag == LTO_null) + return NULL; + + r = GGC_CNEW (struct eh_region_d); + r->index = lto_input_sleb128 (ib); + + gcc_assert (r->index == ix); + + /* Read all the region pointers as region numbers. We'll fix up + the pointers once the whole array has been read. */ + r->outer = (eh_region) (intptr_t) lto_input_sleb128 (ib); + r->inner = (eh_region) (intptr_t) lto_input_sleb128 (ib); + r->next_peer = (eh_region) (intptr_t) lto_input_sleb128 (ib); + + switch (tag) + { + case LTO_ert_cleanup: + r->type = ERT_CLEANUP; + break; + + case LTO_ert_try: + { + struct eh_catch_d *last_catch; + r->type = ERT_TRY; + r->u.eh_try.first_catch = lto_input_eh_catch_list (ib, data_in, + &last_catch); + r->u.eh_try.last_catch = last_catch; + break; + } + + case LTO_ert_allowed_exceptions: + { + tree l; + + r->type = ERT_ALLOWED_EXCEPTIONS; + r->u.allowed.type_list = lto_input_tree (ib, data_in); + r->u.allowed.label = lto_input_tree (ib, data_in); + r->u.allowed.filter = lto_input_uleb128 (ib); + + for (l = r->u.allowed.type_list; l ; l = TREE_CHAIN (l)) + add_type_for_runtime (TREE_VALUE (l)); + } + break; + + case LTO_ert_must_not_throw: + r->type = ERT_MUST_NOT_THROW; + r->u.must_not_throw.failure_decl = lto_input_tree (ib, data_in); + r->u.must_not_throw.failure_loc = lto_input_location (ib, data_in); + break; + + default: + gcc_unreachable (); + } + + r->landing_pads = (eh_landing_pad) (intptr_t) lto_input_sleb128 (ib); + + return r; +} + + +/* Read and return EH landing pad IX from input block IB, using descriptors + in DATA_IN. */ + +static eh_landing_pad +input_eh_lp (struct lto_input_block *ib, struct data_in *data_in, int ix) +{ + enum LTO_tags tag; + eh_landing_pad lp; + + /* Read the landing pad header. */ + tag = input_record_start (ib); + if (tag == LTO_null) + return NULL; + + lto_tag_check_range (tag, LTO_eh_landing_pad, LTO_eh_landing_pad); + + lp = GGC_CNEW (struct eh_landing_pad_d); + lp->index = lto_input_sleb128 (ib); + gcc_assert (lp->index == ix); + lp->next_lp = (eh_landing_pad) (intptr_t) lto_input_sleb128 (ib); + lp->region = (eh_region) (intptr_t) lto_input_sleb128 (ib); + lp->post_landing_pad = lto_input_tree (ib, data_in); + + return lp; +} + + +/* After reading the EH regions, pointers to peer and children regions + are region numbers. This converts all these region numbers into + real pointers into the rematerialized regions for FN. ROOT_REGION + is the region number for the root EH region in FN. */ + +static void +fixup_eh_region_pointers (struct function *fn, HOST_WIDE_INT root_region) +{ + unsigned i; + VEC(eh_region,gc) *eh_array = fn->eh->region_array; + VEC(eh_landing_pad,gc) *lp_array = fn->eh->lp_array; + eh_region r; + eh_landing_pad lp; + + gcc_assert (eh_array && lp_array); + + gcc_assert (root_region >= 0); + fn->eh->region_tree = VEC_index (eh_region, eh_array, root_region); + +#define FIXUP_EH_REGION(r) (r) = VEC_index (eh_region, eh_array, \ + (HOST_WIDE_INT) (intptr_t) (r)) +#define FIXUP_EH_LP(p) (p) = VEC_index (eh_landing_pad, lp_array, \ + (HOST_WIDE_INT) (intptr_t) (p)) + + /* Convert all the index numbers stored in pointer fields into + pointers to the corresponding slots in the EH region array. */ + for (i = 0; VEC_iterate (eh_region, eh_array, i, r); i++) + { + /* The array may contain NULL regions. */ + if (r == NULL) + continue; + + gcc_assert (i == (unsigned) r->index); + FIXUP_EH_REGION (r->outer); + FIXUP_EH_REGION (r->inner); + FIXUP_EH_REGION (r->next_peer); + FIXUP_EH_LP (r->landing_pads); + } + + /* Convert all the index numbers stored in pointer fields into + pointers to the corresponding slots in the EH landing pad array. */ + for (i = 0; VEC_iterate (eh_landing_pad, lp_array, i, lp); i++) + { + /* The array may contain NULL landing pads. */ + if (lp == NULL) + continue; + + gcc_assert (i == (unsigned) lp->index); + FIXUP_EH_LP (lp->next_lp); + FIXUP_EH_REGION (lp->region); + } + +#undef FIXUP_EH_REGION +#undef FIXUP_EH_LP +} + + +/* Initialize EH support. */ + +static void +lto_init_eh (void) +{ + /* Contrary to most other FEs, we only initialize EH support when at + least one of the files in the set contains exception regions in + it. Since this happens much later than the call to init_eh in + lang_dependent_init, we have to set flag_exceptions and call + init_eh again to initialize the EH tables. */ + flag_exceptions = 1; + init_eh (); + + /* Initialize dwarf2 tables. Since dwarf2out_do_frame() returns + true only when exceptions are enabled, this initialization is + never done during lang_dependent_init. */ +#if defined DWARF2_DEBUGGING_INFO || defined DWARF2_UNWIND_INFO + if (dwarf2out_do_frame ()) + dwarf2out_frame_init (); +#endif +} + + +/* Read the exception table for FN from IB using the data descriptors + in DATA_IN. */ + +static void +input_eh_regions (struct lto_input_block *ib, struct data_in *data_in, + struct function *fn) +{ + HOST_WIDE_INT i, root_region, len; + enum LTO_tags tag; + static bool eh_initialized_p = false; + + tag = input_record_start (ib); + if (tag == LTO_null) + return; + + lto_tag_check_range (tag, LTO_eh_table, LTO_eh_table); + + /* If the file contains EH regions, then it was compiled with + -fexceptions. In that case, initialize the backend EH + machinery. */ + if (!eh_initialized_p) + { + lto_init_eh (); + eh_initialized_p = true; + } + + gcc_assert (fn->eh); + + root_region = lto_input_sleb128 (ib); + gcc_assert (root_region == (int) root_region); + + /* Read the EH region array. */ + len = lto_input_sleb128 (ib); + gcc_assert (len == (int) len); + if (len > 0) + { + VEC_safe_grow (eh_region, gc, fn->eh->region_array, len); + for (i = 0; i < len; i++) + { + eh_region r = input_eh_region (ib, data_in, i); + VEC_replace (eh_region, fn->eh->region_array, i, r); + } + } + + /* Read the landing pads. */ + len = lto_input_sleb128 (ib); + gcc_assert (len == (int) len); + if (len > 0) + { + VEC_safe_grow (eh_landing_pad, gc, fn->eh->lp_array, len); + for (i = 0; i < len; i++) + { + eh_landing_pad lp = input_eh_lp (ib, data_in, i); + VEC_replace (eh_landing_pad, fn->eh->lp_array, i, lp); + } + } + + /* Read the runtime type data. */ + len = lto_input_sleb128 (ib); + gcc_assert (len == (int) len); + if (len > 0) + { + VEC_safe_grow (tree, gc, fn->eh->ttype_data, len); + for (i = 0; i < len; i++) + { + tree ttype = lto_input_tree (ib, data_in); + VEC_replace (tree, fn->eh->ttype_data, i, ttype); + } + } + + /* Read the table of action chains. */ + len = lto_input_sleb128 (ib); + gcc_assert (len == (int) len); + if (len > 0) + { + if (targetm.arm_eabi_unwinder) + { + VEC_safe_grow (tree, gc, fn->eh->ehspec_data.arm_eabi, len); + for (i = 0; i < len; i++) + { + tree t = lto_input_tree (ib, data_in); + VEC_replace (tree, fn->eh->ehspec_data.arm_eabi, i, t); + } + } + else + { + VEC_safe_grow (uchar, gc, fn->eh->ehspec_data.other, len); + for (i = 0; i < len; i++) + { + uchar c = lto_input_1_unsigned (ib); + VEC_replace (uchar, fn->eh->ehspec_data.other, i, c); + } + } + } + + /* Reconstruct the EH region tree by fixing up the peer/children + pointers. */ + fixup_eh_region_pointers (fn, root_region); + + tag = input_record_start (ib); + lto_tag_check_range (tag, LTO_null, LTO_null); +} + + +/* Make a new basic block with index INDEX in function FN. */ + +static basic_block +make_new_block (struct function *fn, unsigned int index) +{ + basic_block bb = alloc_block (); + bb->index = index; + SET_BASIC_BLOCK_FOR_FUNCTION (fn, index, bb); + bb->il.gimple = GGC_CNEW (struct gimple_bb_info); + n_basic_blocks_for_function (fn)++; + bb->flags = 0; + set_bb_seq (bb, gimple_seq_alloc ()); + return bb; +} + + +/* Read the CFG for function FN from input block IB. */ + +static void +input_cfg (struct lto_input_block *ib, struct function *fn) +{ + unsigned int bb_count; + basic_block p_bb; + unsigned int i; + int index; + + init_empty_tree_cfg_for_function (fn); + init_ssa_operands (); + + profile_status_for_function (fn) = + (enum profile_status_d) lto_input_uleb128 (ib); + + bb_count = lto_input_uleb128 (ib); + + last_basic_block_for_function (fn) = bb_count; + if (bb_count > VEC_length (basic_block, basic_block_info_for_function (fn))) + VEC_safe_grow_cleared (basic_block, gc, + basic_block_info_for_function (fn), bb_count); + + if (bb_count > VEC_length (basic_block, label_to_block_map_for_function (fn))) + VEC_safe_grow_cleared (basic_block, gc, + label_to_block_map_for_function (fn), bb_count); + + index = lto_input_sleb128 (ib); + while (index != -1) + { + basic_block bb = BASIC_BLOCK_FOR_FUNCTION (fn, index); + unsigned int edge_count; + + if (bb == NULL) + bb = make_new_block (fn, index); + + edge_count = lto_input_uleb128 (ib); + + /* Connect up the CFG. */ + for (i = 0; i < edge_count; i++) + { + unsigned int dest_index; + unsigned int edge_flags; + basic_block dest; + int probability; + gcov_type count; + edge e; + + dest_index = lto_input_uleb128 (ib); + probability = (int) lto_input_sleb128 (ib); + count = (gcov_type) lto_input_sleb128 (ib); + edge_flags = lto_input_uleb128 (ib); + + dest = BASIC_BLOCK_FOR_FUNCTION (fn, dest_index); + + if (dest == NULL) + dest = make_new_block (fn, dest_index); + + e = make_edge (bb, dest, edge_flags); + e->probability = probability; + e->count = count; + } + + index = lto_input_sleb128 (ib); + } + + p_bb = ENTRY_BLOCK_PTR_FOR_FUNCTION(fn); + index = lto_input_sleb128 (ib); + while (index != -1) + { + basic_block bb = BASIC_BLOCK_FOR_FUNCTION (fn, index); + bb->prev_bb = p_bb; + p_bb->next_bb = bb; + p_bb = bb; + index = lto_input_sleb128 (ib); + } +} + + +/* Read a PHI function for basic block BB in function FN. DATA_IN is + the file being read. IB is the input block to use for reading. */ + +static gimple +input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in, + struct function *fn) +{ + unsigned HOST_WIDE_INT ix; + tree phi_result; + int i, len; + gimple result; + + ix = lto_input_uleb128 (ib); + phi_result = VEC_index (tree, SSANAMES (fn), ix); + len = EDGE_COUNT (bb->preds); + result = create_phi_node (phi_result, bb); + SSA_NAME_DEF_STMT (phi_result) = result; + + /* We have to go through a lookup process here because the preds in the + reconstructed graph are generally in a different order than they + were in the original program. */ + for (i = 0; i < len; i++) + { + tree def = lto_input_tree (ib, data_in); + int src_index = lto_input_uleb128 (ib); + location_t arg_loc = lto_input_location (ib, data_in); + basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index); + + edge e = NULL; + int j; + + for (j = 0; j < len; j++) + if (EDGE_PRED (bb, j)->src == sbb) + { + e = EDGE_PRED (bb, j); + break; + } + + add_phi_arg (result, def, e, arg_loc); + } + + return result; +} + + +/* Read the SSA names array for function FN from DATA_IN using input + block IB. */ + +static void +input_ssa_names (struct lto_input_block *ib, struct data_in *data_in, + struct function *fn) +{ + unsigned int i, size; + + size = lto_input_uleb128 (ib); + init_ssanames (fn, size); + + i = lto_input_uleb128 (ib); + while (i) + { + tree ssa_name, name; + bool is_default_def; + + /* Skip over the elements that had been freed. */ + while (VEC_length (tree, SSANAMES (fn)) < i) + VEC_quick_push (tree, SSANAMES (fn), NULL_TREE); + + is_default_def = (lto_input_1_unsigned (ib) != 0); + name = lto_input_tree (ib, data_in); + ssa_name = make_ssa_name_fn (fn, name, gimple_build_nop ()); + + if (is_default_def) + set_default_def (SSA_NAME_VAR (ssa_name), ssa_name); + + i = lto_input_uleb128 (ib); + } +} + + +/* Fixup the reference tree OP for replaced VAR_DECLs with mismatched + types. */ + +static void +maybe_fixup_handled_component (tree op) +{ + tree decl_type; + tree wanted_type; + + while (handled_component_p (TREE_OPERAND (op, 0))) + op = TREE_OPERAND (op, 0); + if (TREE_CODE (TREE_OPERAND (op, 0)) != VAR_DECL) + return; + + decl_type = TREE_TYPE (TREE_OPERAND (op, 0)); + + switch (TREE_CODE (op)) + { + case COMPONENT_REF: + /* The DECL_CONTEXT of the field-decl is the record type we look for. */ + wanted_type = DECL_CONTEXT (TREE_OPERAND (op, 1)); + break; + + case ARRAY_REF: + if (TREE_CODE (decl_type) == ARRAY_TYPE + && (TREE_TYPE (decl_type) == TREE_TYPE (op) + || useless_type_conversion_p (TREE_TYPE (op), + TREE_TYPE (decl_type)))) + return; + /* An unknown size array type should be ok. But we do not + lower the lower bound in all cases - ugh. */ + wanted_type = build_array_type (TREE_TYPE (op), NULL_TREE); + break; + + case ARRAY_RANGE_REF: + if (TREE_CODE (decl_type) == ARRAY_TYPE + && (TREE_TYPE (decl_type) == TREE_TYPE (TREE_TYPE (op)) + || useless_type_conversion_p (TREE_TYPE (TREE_TYPE (op)), + TREE_TYPE (decl_type)))) + return; + /* An unknown size array type should be ok. But we do not + lower the lower bound in all cases - ugh. */ + wanted_type = build_array_type (TREE_TYPE (TREE_TYPE (op)), NULL_TREE); + break; + + case BIT_FIELD_REF: + case VIEW_CONVERT_EXPR: + /* Very nice - nothing to do. */ + return; + + case REALPART_EXPR: + case IMAGPART_EXPR: + if (TREE_CODE (decl_type) == COMPLEX_TYPE + && (TREE_TYPE (decl_type) == TREE_TYPE (op) + || useless_type_conversion_p (TREE_TYPE (op), + TREE_TYPE (decl_type)))) + return; + wanted_type = build_complex_type (TREE_TYPE (op)); + break; + + default: + gcc_unreachable (); + } + + if (!useless_type_conversion_p (wanted_type, decl_type)) + TREE_OPERAND (op, 0) = build1 (VIEW_CONVERT_EXPR, wanted_type, + TREE_OPERAND (op, 0)); +} + +/* Fixup reference tree operands for substituted prevailing decls + with mismatched types in STMT. */ + +static void +maybe_fixup_decls (gimple stmt) +{ + /* We have to fixup replaced decls here in case there were + inter-TU type mismatches. Catch the most common cases + for now - this way we'll get testcases for the rest as + the type verifier will complain. */ + if (gimple_assign_single_p (stmt)) + { + tree lhs = gimple_assign_lhs (stmt); + tree rhs = gimple_assign_rhs1 (stmt); + + /* First catch loads and aggregate copies by adjusting the rhs. */ + if (TREE_CODE (rhs) == VAR_DECL) + { + if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) + gimple_assign_set_rhs1 (stmt, build1 (VIEW_CONVERT_EXPR, + TREE_TYPE (lhs), rhs)); + } + else if (handled_component_p (rhs)) + maybe_fixup_handled_component (rhs); + /* Then catch scalar stores. */ + else if (TREE_CODE (lhs) == VAR_DECL) + { + if (!useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (rhs))) + gimple_assign_set_lhs (stmt, build1 (VIEW_CONVERT_EXPR, + TREE_TYPE (rhs), lhs)); + } + else if (handled_component_p (lhs)) + maybe_fixup_handled_component (lhs); + } + else if (is_gimple_call (stmt)) + { + tree lhs = gimple_call_lhs (stmt); + + if (lhs && TREE_CODE (lhs) == VAR_DECL) + { + if (!useless_type_conversion_p (TREE_TYPE (lhs), + gimple_call_return_type (stmt))) + gimple_call_set_lhs (stmt, build1 (VIEW_CONVERT_EXPR, + gimple_call_return_type (stmt), + lhs)); + } + else if (lhs && handled_component_p (lhs)) + maybe_fixup_handled_component (lhs); + + /* Arguments, especially for varargs functions will be funny... */ + } +} + +/* Read a statement with tag TAG in function FN from block IB using + descriptors in DATA_IN. */ + +static gimple +input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, + struct function *fn, enum LTO_tags tag) +{ + gimple stmt; + enum gimple_code code; + unsigned HOST_WIDE_INT num_ops; + size_t i; + struct bitpack_d *bp; + + code = lto_tag_to_gimple_code (tag); + + /* Read the tuple header. */ + bp = lto_input_bitpack (ib); + num_ops = bp_unpack_value (bp, sizeof (unsigned) * 8); + stmt = gimple_alloc (code, num_ops); + stmt->gsbase.no_warning = bp_unpack_value (bp, 1); + if (is_gimple_assign (stmt)) + stmt->gsbase.nontemporal_move = bp_unpack_value (bp, 1); + stmt->gsbase.has_volatile_ops = bp_unpack_value (bp, 1); + stmt->gsbase.subcode = bp_unpack_value (bp, 16); + bitpack_delete (bp); + + /* Read location information. */ + gimple_set_location (stmt, lto_input_location (ib, data_in)); + + /* Read lexical block reference. */ + gimple_set_block (stmt, lto_input_tree (ib, data_in)); + + /* Read in all the operands. */ + switch (code) + { + case GIMPLE_RESX: + gimple_resx_set_region (stmt, lto_input_sleb128 (ib)); + break; + + case GIMPLE_EH_MUST_NOT_THROW: + gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in)); + break; + + case GIMPLE_EH_DISPATCH: + gimple_eh_dispatch_set_region (stmt, lto_input_sleb128 (ib)); + break; + + case GIMPLE_ASM: + { + /* FIXME lto. Move most of this into a new gimple_asm_set_string(). */ + tree str; + stmt->gimple_asm.ni = lto_input_uleb128 (ib); + stmt->gimple_asm.no = lto_input_uleb128 (ib); + stmt->gimple_asm.nc = lto_input_uleb128 (ib); + str = input_string_cst (data_in, ib); + stmt->gimple_asm.string = TREE_STRING_POINTER (str); + } + /* Fallthru */ + + case GIMPLE_ASSIGN: + case GIMPLE_CALL: + case GIMPLE_RETURN: + case GIMPLE_SWITCH: + case GIMPLE_LABEL: + case GIMPLE_COND: + case GIMPLE_GOTO: + case GIMPLE_DEBUG: + for (i = 0; i < num_ops; i++) + { + tree op = lto_input_tree (ib, data_in); + gimple_set_op (stmt, i, op); + + /* Fixup FIELD_DECLs. */ + while (op && handled_component_p (op)) + { + if (TREE_CODE (op) == COMPONENT_REF) + { + tree field, type, tem; + field = TREE_OPERAND (op, 1); + type = DECL_CONTEXT (field); + for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem)) + { + if (tem == field + || (TREE_TYPE (tem) == TREE_TYPE (field) + && (DECL_FIELD_OFFSET (tem) + == DECL_FIELD_OFFSET (field)) + && (DECL_FIELD_BIT_OFFSET (tem) + == DECL_FIELD_BIT_OFFSET (field)) + && (DECL_OFFSET_ALIGN (tem) + == DECL_OFFSET_ALIGN (field)))) + break; + } + /* In case of type mismatches across units we can fail + to unify some types and thus not find a proper + field-decl here. Just do nothing in this case. */ + if (tem != NULL_TREE) + TREE_OPERAND (op, 1) = tem; + } + + op = TREE_OPERAND (op, 0); + } + } + break; + + case GIMPLE_NOP: + case GIMPLE_PREDICT: + break; + + default: + internal_error ("bytecode stream: unknown GIMPLE statement tag %s", + lto_tag_name (tag)); + } + + /* Update the properties of symbols, SSA names and labels associated + with STMT. */ + if (code == GIMPLE_ASSIGN || code == GIMPLE_CALL) + { + tree lhs = gimple_get_lhs (stmt); + if (lhs && TREE_CODE (lhs) == SSA_NAME) + SSA_NAME_DEF_STMT (lhs) = stmt; + } + else if (code == GIMPLE_LABEL) + gcc_assert (emit_label_in_global_context_p (gimple_label_label (stmt)) + || DECL_CONTEXT (gimple_label_label (stmt)) == fn->decl); + else if (code == GIMPLE_ASM) + { + unsigned i; + + for (i = 0; i < gimple_asm_noutputs (stmt); i++) + { + tree op = TREE_VALUE (gimple_asm_output_op (stmt, i)); + if (TREE_CODE (op) == SSA_NAME) + SSA_NAME_DEF_STMT (op) = stmt; + } + } + + /* Fixup reference tree operands for substituted prevailing decls + with mismatched types. */ + maybe_fixup_decls (stmt); + + /* Mark the statement modified so its operand vectors can be filled in. */ + gimple_set_modified (stmt, true); + + return stmt; +} + + +/* Read a basic block with tag TAG from DATA_IN using input block IB. + FN is the function being processed. */ + +static void +input_bb (struct lto_input_block *ib, enum LTO_tags tag, + struct data_in *data_in, struct function *fn) +{ + unsigned int index; + basic_block bb; + gimple_stmt_iterator bsi; + + /* This routine assumes that CFUN is set to FN, as it needs to call + basic GIMPLE routines that use CFUN. */ + gcc_assert (cfun == fn); + + index = lto_input_uleb128 (ib); + bb = BASIC_BLOCK_FOR_FUNCTION (fn, index); + + bb->count = lto_input_sleb128 (ib); + bb->loop_depth = lto_input_sleb128 (ib); + bb->frequency = lto_input_sleb128 (ib); + bb->flags = lto_input_sleb128 (ib); + + /* LTO_bb1 has statements. LTO_bb0 does not. */ + if (tag == LTO_bb0) + return; + + bsi = gsi_start_bb (bb); + tag = input_record_start (ib); + while (tag) + { + gimple stmt = input_gimple_stmt (ib, data_in, fn, tag); + + /* Change debug stmts to nops on-the-fly if we do not have VTA enabled. + This allows us to build for example static libs with debugging + enabled and do the final link without. */ + if (!MAY_HAVE_DEBUG_STMTS + && is_gimple_debug (stmt)) + stmt = gimple_build_nop (); + + find_referenced_vars_in (stmt); + gsi_insert_after (&bsi, stmt, GSI_NEW_STMT); + + /* After the statement, expect a 0 delimiter or the EH region + that the previous statement belongs to. */ + tag = input_record_start (ib); + lto_tag_check_set (tag, 2, LTO_eh_region, LTO_null); + + if (tag == LTO_eh_region) + { + HOST_WIDE_INT region = lto_input_sleb128 (ib); + gcc_assert (region == (int) region); + add_stmt_to_eh_lp (stmt, region); + } + + tag = input_record_start (ib); + } + + tag = input_record_start (ib); + while (tag) + { + gimple phi = input_phi (ib, bb, data_in, fn); + find_referenced_vars_in (phi); + tag = input_record_start (ib); + } +} + +/* Go through all NODE edges and fixup call_stmt pointers + so they point to STMTS. */ + +static void +fixup_call_stmt_edges_1 (struct cgraph_node *node, gimple *stmts) +{ + struct cgraph_edge *cedge; + for (cedge = node->callees; cedge; cedge = cedge->next_callee) + cedge->call_stmt = stmts[cedge->lto_stmt_uid]; +} + +/* Fixup call_stmt pointers in NODE and all clones. */ + +static void +fixup_call_stmt_edges (struct cgraph_node *orig, gimple *stmts) +{ + struct cgraph_node *node; + + while (orig->clone_of) + orig = orig->clone_of; + + fixup_call_stmt_edges_1 (orig, stmts); + if (orig->clones) + for (node = orig->clones; node != orig;) + { + fixup_call_stmt_edges_1 (node, stmts); + if (node->clones) + node = node->clones; + else if (node->next_sibling_clone) + node = node->next_sibling_clone; + else + { + while (node != orig && !node->next_sibling_clone) + node = node->clone_of; + if (node != orig) + node = node->next_sibling_clone; + } + } +} + +/* Read the body of function FN_DECL from DATA_IN using input block IB. */ + +static void +input_function (tree fn_decl, struct data_in *data_in, + struct lto_input_block *ib) +{ + struct function *fn; + enum LTO_tags tag; + gimple *stmts; + basic_block bb; + struct bitpack_d *bp; + + fn = DECL_STRUCT_FUNCTION (fn_decl); + tag = input_record_start (ib); + clear_line_info (data_in); + + gimple_register_cfg_hooks (); + lto_tag_check (tag, LTO_function); + + /* Read all the attributes for FN. */ + bp = lto_input_bitpack (ib); + fn->is_thunk = bp_unpack_value (bp, 1); + fn->has_local_explicit_reg_vars = bp_unpack_value (bp, 1); + fn->after_tree_profile = bp_unpack_value (bp, 1); + fn->returns_pcc_struct = bp_unpack_value (bp, 1); + fn->returns_struct = bp_unpack_value (bp, 1); + fn->always_inline_functions_inlined = bp_unpack_value (bp, 1); + fn->after_inlining = bp_unpack_value (bp, 1); + fn->dont_save_pending_sizes_p = bp_unpack_value (bp, 1); + fn->stdarg = bp_unpack_value (bp, 1); + fn->has_nonlocal_label = bp_unpack_value (bp, 1); + fn->calls_alloca = bp_unpack_value (bp, 1); + fn->calls_setjmp = bp_unpack_value (bp, 1); + fn->function_frequency = (enum function_frequency) bp_unpack_value (bp, 2); + fn->va_list_fpr_size = bp_unpack_value (bp, 8); + fn->va_list_gpr_size = bp_unpack_value (bp, 8); + bitpack_delete (bp); + + /* Read the static chain and non-local goto save area. */ + fn->static_chain_decl = lto_input_tree (ib, data_in); + fn->nonlocal_goto_save_area = lto_input_tree (ib, data_in); + + /* Read all the local symbols. */ + fn->local_decls = lto_input_tree (ib, data_in); + + /* Read all the SSA names. */ + input_ssa_names (ib, data_in, fn); + + /* Read the exception handling regions in the function. */ + input_eh_regions (ib, data_in, fn); + + /* Read the tree of lexical scopes for the function. */ + DECL_INITIAL (fn_decl) = lto_input_tree (ib, data_in); + gcc_assert (DECL_INITIAL (fn_decl)); + DECL_SAVED_TREE (fn_decl) = NULL_TREE; + + /* Read all function arguments. */ + DECL_ARGUMENTS (fn_decl) = lto_input_tree (ib, data_in); + + /* Read all the basic blocks. */ + tag = input_record_start (ib); + while (tag) + { + input_bb (ib, tag, data_in, fn); + tag = input_record_start (ib); + } + + /* Fix up the call statements that are mentioned in the callgraph + edges. */ + renumber_gimple_stmt_uids (); + stmts = (gimple *) xcalloc (gimple_stmt_max_uid (fn), sizeof (gimple)); + FOR_ALL_BB (bb) + { + gimple_stmt_iterator bsi; + for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) + { + gimple stmt = gsi_stmt (bsi); + stmts[gimple_uid (stmt)] = stmt; + } + } + + /* Set the gimple body to the statement sequence in the entry + basic block. FIXME lto, this is fairly hacky. The existence + of a gimple body is used by the cgraph routines, but we should + really use the presence of the CFG. */ + { + edge_iterator ei = ei_start (ENTRY_BLOCK_PTR->succs); + gimple_set_body (fn_decl, bb_seq (ei_edge (ei)->dest)); + } + + fixup_call_stmt_edges (cgraph_node (fn_decl), stmts); + + update_ssa (TODO_update_ssa_only_virtuals); + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + free (stmts); +} + + +/* Read initializer expressions for public statics. DATA_IN is the + file being read. IB is the input block used for reading. */ + +static void +input_alias_pairs (struct lto_input_block *ib, struct data_in *data_in) +{ + tree var; + + clear_line_info (data_in); + + /* Skip over all the unreferenced globals. */ + do + var = lto_input_tree (ib, data_in); + while (var); + + var = lto_input_tree (ib, data_in); + while (var) + { + const char *orig_name, *new_name; + alias_pair *p; + + p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL); + p->decl = var; + p->target = lto_input_tree (ib, data_in); + + /* If the target is a static object, we may have registered a + new name for it to avoid clashes between statics coming from + different files. In that case, use the new name. */ + orig_name = IDENTIFIER_POINTER (p->target); + new_name = lto_get_decl_name_mapping (data_in->file_data, orig_name); + if (strcmp (orig_name, new_name) != 0) + p->target = get_identifier (new_name); + + var = lto_input_tree (ib, data_in); + } +} + + +/* Read the body from DATA for function FN_DECL and fill it in. + FILE_DATA are the global decls and types. SECTION_TYPE is either + LTO_section_function_body or LTO_section_static_initializer. If + section type is LTO_section_function_body, FN must be the decl for + that function. */ + +static void +lto_read_body (struct lto_file_decl_data *file_data, tree fn_decl, + const char *data, enum lto_section_type section_type) +{ + const struct lto_function_header *header; + struct data_in *data_in; + int32_t cfg_offset; + int32_t main_offset; + int32_t string_offset; + struct lto_input_block ib_cfg; + struct lto_input_block ib_main; + + header = (const struct lto_function_header *) data; + cfg_offset = sizeof (struct lto_function_header); + main_offset = cfg_offset + header->cfg_size; + string_offset = main_offset + header->main_size; + + LTO_INIT_INPUT_BLOCK (ib_cfg, + data + cfg_offset, + 0, + header->cfg_size); + + LTO_INIT_INPUT_BLOCK (ib_main, + data + main_offset, + 0, + header->main_size); + + data_in = lto_data_in_create (file_data, data + string_offset, + header->string_size, NULL); + + /* Make sure the file was generated by the exact same compiler. */ + lto_check_version (header->lto_header.major_version, + header->lto_header.minor_version); + + if (section_type == LTO_section_function_body) + { + struct function *fn = DECL_STRUCT_FUNCTION (fn_decl); + struct lto_in_decl_state *decl_state; + + push_cfun (fn); + init_tree_ssa (fn); + + /* Use the function's decl state. */ + decl_state = lto_get_function_in_decl_state (file_data, fn_decl); + gcc_assert (decl_state); + file_data->current_decl_state = decl_state; + + input_cfg (&ib_cfg, fn); + + /* Set up the struct function. */ + input_function (fn_decl, data_in, &ib_main); + + /* We should now be in SSA. */ + cfun->gimple_df->in_ssa_p = true; + + /* Fill in properties we know hold for the rebuilt CFG. */ + cfun->curr_properties = PROP_ssa + | PROP_cfg + | PROP_gimple_any + | PROP_gimple_lcf + | PROP_gimple_leh + | PROP_referenced_vars; + + /* Restore decl state */ + file_data->current_decl_state = file_data->global_decl_state; + + /* FIXME: ipa_transforms_to_apply holds list of passes that have optimization + summaries computed and needs to apply changes. At the moment WHOPR only + supports inlining, so we can push it here by hand. In future we need to stream + this field into ltrans compilation. This will also need to move the field + from struct function into cgraph node where it belongs. */ + if (flag_ltrans && !cgraph_node (fn_decl)->global.inlined_to) + VEC_safe_push (ipa_opt_pass, heap, + cfun->ipa_transforms_to_apply, + (ipa_opt_pass)&pass_ipa_inline); + pop_cfun (); + } + else + { + input_alias_pairs (&ib_main, data_in); + } + + clear_line_info (data_in); + lto_data_in_delete (data_in); +} + + +/* Read the body of FN_DECL using DATA. FILE_DATA holds the global + decls and types. */ + +void +lto_input_function_body (struct lto_file_decl_data *file_data, + tree fn_decl, const char *data) +{ + current_function_decl = fn_decl; + lto_read_body (file_data, fn_decl, data, LTO_section_function_body); +} + + +/* Read in VAR_DECL using DATA. FILE_DATA holds the global decls and + types. */ + +void +lto_input_constructors_and_inits (struct lto_file_decl_data *file_data, + const char *data) +{ + lto_read_body (file_data, NULL, data, LTO_section_static_initializer); +} + + +/* Return the resolution for the decl with index INDEX from DATA_IN. */ + +static enum ld_plugin_symbol_resolution +get_resolution (struct data_in *data_in, unsigned index) +{ + if (data_in->globals_resolution) + { + ld_plugin_symbol_resolution_t ret; + gcc_assert (index < VEC_length (ld_plugin_symbol_resolution_t, + data_in->globals_resolution)); + ret = VEC_index (ld_plugin_symbol_resolution_t, + data_in->globals_resolution, + index); + gcc_assert (ret != LDPR_UNKNOWN); + return ret; + } + else + /* Delay resolution finding until decl merging. */ + return LDPR_UNKNOWN; +} + + +/* Unpack all the non-pointer fields of the TS_BASE structure of + expression EXPR from bitpack BP. */ + +static void +unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr) +{ + /* Note that the code for EXPR has already been unpacked to create EXPR in + lto_materialize_tree. */ + if (!TYPE_P (expr)) + { + TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1); + + /* TREE_PUBLIC is used on types to indicate that the type + has a TYPE_CACHED_VALUES vector. This is not streamed out, + so we skip it here. */ + TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1); + } + TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1); + if (DECL_P (expr)) + DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1); + else if (TYPE_P (expr)) + TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_USED (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1); + TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1); + if (TYPE_P (expr)) + TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1); + if (TREE_CODE (expr) == SSA_NAME) + SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1); +} + + +/* Unpack all the non-pointer fields of the TS_REAL_CST structure of + expression EXPR from bitpack BP. */ + +static void +unpack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr) +{ + unsigned i; + REAL_VALUE_TYPE r; + REAL_VALUE_TYPE *rp; + + r.cl = (unsigned) bp_unpack_value (bp, 2); + r.decimal = (unsigned) bp_unpack_value (bp, 1); + r.sign = (unsigned) bp_unpack_value (bp, 1); + r.signalling = (unsigned) bp_unpack_value (bp, 1); + r.canonical = (unsigned) bp_unpack_value (bp, 1); + r.uexp = (unsigned) bp_unpack_value (bp, EXP_BITS); + for (i = 0; i < SIGSZ; i++) + r.sig[i] = (unsigned long) bp_unpack_value (bp, HOST_BITS_PER_LONG); + + rp = GGC_NEW (REAL_VALUE_TYPE); + memcpy (rp, &r, sizeof (REAL_VALUE_TYPE)); + TREE_REAL_CST_PTR (expr) = rp; +} + + +/* Unpack all the non-pointer fields of the TS_FIXED_CST structure of + expression EXPR from bitpack BP. */ + +static void +unpack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr) +{ + struct fixed_value fv; + + fv.data.low = (HOST_WIDE_INT) bp_unpack_value (bp, HOST_BITS_PER_WIDE_INT); + fv.data.high = (HOST_WIDE_INT) bp_unpack_value (bp, HOST_BITS_PER_WIDE_INT); + TREE_FIXED_CST (expr) = fv; +} + + +/* Unpack all the non-pointer fields of the TS_DECL_COMMON structure + of expression EXPR from bitpack BP. */ + +static void +unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr) +{ + DECL_MODE (expr) = (enum machine_mode) bp_unpack_value (bp, 8); + DECL_NONLOCAL (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_VIRTUAL_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_IGNORED_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_DEBUG_EXPR_IS_FROM (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_ALIGN (expr) = (unsigned) bp_unpack_value (bp, HOST_BITS_PER_INT); + + if (TREE_CODE (expr) == LABEL_DECL) + { + DECL_ERROR_ISSUED (expr) = (unsigned) bp_unpack_value (bp, 1); + EH_LANDING_PAD_NR (expr) = (int) bp_unpack_value (bp, HOST_BITS_PER_INT); + + /* Always assume an initial value of -1 for LABEL_DECL_UID to + force gimple_set_bb to recreate label_to_block_map. */ + LABEL_DECL_UID (expr) = -1; + } + + if (TREE_CODE (expr) == FIELD_DECL) + { + unsigned HOST_WIDE_INT off_align; + DECL_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_NONADDRESSABLE_P (expr) = (unsigned) bp_unpack_value (bp, 1); + off_align = (unsigned HOST_WIDE_INT) bp_unpack_value (bp, 8); + SET_DECL_OFFSET_ALIGN (expr, off_align); + } + + if (TREE_CODE (expr) == RESULT_DECL + || TREE_CODE (expr) == PARM_DECL + || TREE_CODE (expr) == VAR_DECL) + { + DECL_BY_REFERENCE (expr) = (unsigned) bp_unpack_value (bp, 1); + if (TREE_CODE (expr) == VAR_DECL + || TREE_CODE (expr) == PARM_DECL) + DECL_HAS_VALUE_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_RESTRICTED_P (expr) = (unsigned) bp_unpack_value (bp, 1); + } +} + + +/* Unpack all the non-pointer fields of the TS_DECL_WRTL structure + of expression EXPR from bitpack BP. */ + +static void +unpack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr) +{ + DECL_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1); +} + + +/* Unpack all the non-pointer fields of the TS_DECL_WITH_VIS structure + of expression EXPR from bitpack BP. */ + +static void +unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) +{ + DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp, 2); + DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp, 1); + + if (TREE_CODE (expr) == VAR_DECL) + { + DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp, 3); + } + + if (VAR_OR_FUNCTION_DECL_P (expr)) + { + priority_type p; + p = (priority_type) bp_unpack_value (bp, HOST_BITS_PER_SHORT); + SET_DECL_INIT_PRIORITY (expr, p); + } +} + + +/* Unpack all the non-pointer fields of the TS_FUNCTION_DECL structure + of expression EXPR from bitpack BP. */ + +static void +unpack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr) +{ + DECL_FUNCTION_CODE (expr) = (enum built_in_function) bp_unpack_value (bp, 11); + DECL_BUILT_IN_CLASS (expr) = (enum built_in_class) bp_unpack_value (bp, 2); + DECL_STATIC_CONSTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_STATIC_DESTRUCTOR (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_UNINLINABLE (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_POSSIBLY_INLINED (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_IS_NOVOPS (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_IS_RETURNS_TWICE (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_IS_MALLOC (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_IS_OPERATOR_NEW (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_DECLARED_INLINE_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_STATIC_CHAIN (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_NO_INLINE_WARNING_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr) + = (unsigned) bp_unpack_value (bp, 1); + DECL_NO_LIMIT_STACK (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_DISREGARD_INLINE_LIMITS (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1); + DECL_LOOPING_CONST_OR_PURE_P (expr) = (unsigned) bp_unpack_value (bp, 1); +} + + +/* Unpack all the non-pointer fields of the TS_TYPE structure + of expression EXPR from bitpack BP. */ + +static void +unpack_ts_type_value_fields (struct bitpack_d *bp, tree expr) +{ + enum machine_mode mode; + + TYPE_PRECISION (expr) = (unsigned) bp_unpack_value (bp, 9); + mode = (enum machine_mode) bp_unpack_value (bp, 7); + SET_TYPE_MODE (expr, mode); + TYPE_STRING_FLAG (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_NO_FORCE_BLK (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_NEEDS_CONSTRUCTING(expr) = (unsigned) bp_unpack_value (bp, 1); + if (TREE_CODE (expr) == UNION_TYPE) + TYPE_TRANSPARENT_UNION (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_PACKED (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_RESTRICT (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr) + = (unsigned) bp_unpack_value (bp, 2); + TYPE_USER_ALIGN (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1); + TYPE_ALIGN (expr) = (unsigned) bp_unpack_value (bp, HOST_BITS_PER_INT); + TYPE_ALIAS_SET (expr) = bp_unpack_value (bp, HOST_BITS_PER_INT); +} + + +/* Unpack all the non-pointer fields of the TS_BLOCK structure + of expression EXPR from bitpack BP. */ + +static void +unpack_ts_block_value_fields (struct bitpack_d *bp, tree expr) +{ + BLOCK_ABSTRACT (expr) = (unsigned) bp_unpack_value (bp, 1); + BLOCK_NUMBER (expr) = (unsigned) bp_unpack_value (bp, 31); +} + + +/* Unpack all the non-pointer fields in EXPR into a bit pack. */ + +static void +unpack_value_fields (struct bitpack_d *bp, tree expr) +{ + enum tree_code code; + + code = TREE_CODE (expr); + + /* Note that all these functions are highly sensitive to changes in + the types and sizes of each of the fields being packed. */ + unpack_ts_base_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST)) + unpack_ts_real_cst_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST)) + unpack_ts_fixed_cst_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + unpack_ts_decl_common_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) + unpack_ts_decl_wrtl_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + unpack_ts_decl_with_vis_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + unpack_ts_function_decl_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE)) + unpack_ts_type_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_BLOCK)) + unpack_ts_block_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME)) + { + /* We only stream the version number of SSA names. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST)) + { + /* This is only used by GENERIC. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE)) + { + /* This is only used by High GIMPLE. */ + gcc_unreachable (); + } +} + + +/* Read a bitpack from input block IB. */ + +struct bitpack_d * +lto_input_bitpack (struct lto_input_block *ib) +{ + unsigned i, num_words; + struct bitpack_d *bp; + + bp = bitpack_create (); + + /* If we are about to read more than a handful of words, something + is wrong. This check is overly strict, but it acts as an early + warning. No streamed object has hundreds of bits in its fields. */ + num_words = lto_input_uleb128 (ib); + gcc_assert (num_words < 20); + + for (i = 0; i < num_words; i++) + { + bitpack_word_t w = lto_input_uleb128 (ib); + VEC_safe_push (bitpack_word_t, heap, bp->values, w); + } + + return bp; +} + + +/* Materialize a new tree from input block IB using descriptors in + DATA_IN. The code for the new tree should match TAG. Store in + *IX_P the index into the reader cache where the new tree is stored. */ + +static tree +lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in, + enum LTO_tags tag, int *ix_p) +{ + struct bitpack_d *bp; + enum tree_code code; + tree result; +#ifdef LTO_STREAMER_DEBUG + HOST_WIDEST_INT orig_address_in_writer; +#endif + HOST_WIDE_INT ix; + + result = NULL_TREE; + + /* Read the header of the node we are about to create. */ + ix = lto_input_sleb128 (ib); + gcc_assert ((int) ix == ix); + *ix_p = (int) ix; + +#ifdef LTO_STREAMER_DEBUG + /* Read the word representing the memory address for the tree + as it was written by the writer. This is useful when + debugging differences between the writer and reader. */ + orig_address_in_writer = lto_input_sleb128 (ib); + gcc_assert ((intptr_t) orig_address_in_writer == orig_address_in_writer); +#endif + + code = lto_tag_to_tree_code (tag); + + /* We should never see an SSA_NAME tree. Only the version numbers of + SSA names are ever written out. See input_ssa_names. */ + gcc_assert (code != SSA_NAME); + + /* Instantiate a new tree using the header data. */ + if (CODE_CONTAINS_STRUCT (code, TS_STRING)) + result = input_string_cst (data_in, ib); + else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER)) + result = input_identifier (data_in, ib); + else if (CODE_CONTAINS_STRUCT (code, TS_VEC)) + { + HOST_WIDE_INT len = lto_input_sleb128 (ib); + result = make_tree_vec (len); + } + else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) + { + unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib); + result = make_tree_binfo (len); + } + else + { + /* All other nodes can be materialized with a raw make_node + call. */ + result = make_node (code); + } + +#ifdef LTO_STREAMER_DEBUG + /* Store the original address of the tree as seen by the writer + in RESULT's aux field. This is useful when debugging streaming + problems. This way, a debugging session can be started on + both writer and reader with a breakpoint using this address + value in both. */ + lto_orig_address_map (result, (intptr_t) orig_address_in_writer); +#endif + + /* Read the bitpack of non-pointer values from IB. */ + bp = lto_input_bitpack (ib); + + /* The first word in BP contains the code of the tree that we + are about to read. */ + code = (enum tree_code) bp_unpack_value (bp, 16); + lto_tag_check (lto_tree_code_to_tag (code), tag); + + /* Unpack all the value fields from BP. */ + unpack_value_fields (bp, result); + bitpack_delete (bp); + + /* Enter RESULT in the reader cache. This will make RESULT + available so that circular references in the rest of the tree + structure can be resolved in subsequent calls to lto_input_tree. */ + lto_streamer_cache_insert_at (data_in->reader_cache, result, ix); + + return result; +} + + +/* Read a chain of tree nodes from input block IB. DATA_IN contains + tables and descriptors for the file being read. */ + +static tree +lto_input_chain (struct lto_input_block *ib, struct data_in *data_in) +{ + int i, count; + tree first, prev, curr; + + first = prev = NULL_TREE; + count = lto_input_sleb128 (ib); + for (i = 0; i < count; i++) + { + curr = lto_input_tree (ib, data_in); + if (prev) + TREE_CHAIN (prev) = curr; + else + first = curr; + + TREE_CHAIN (curr) = NULL_TREE; + prev = curr; + } + + return first; +} + + +/* Read all pointer fields in the TS_COMMON structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + + +static void +lto_input_ts_common_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + TREE_TYPE (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_VECTOR structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_vector_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + TREE_VECTOR_CST_ELTS (expr) = lto_input_chain (ib, data_in); +} + + +/* Read all pointer fields in the TS_COMPLEX structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_complex_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + TREE_REALPART (expr) = lto_input_tree (ib, data_in); + TREE_IMAGPART (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_DECL_MINIMAL structure of EXPR + from input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_decl_minimal_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + DECL_NAME (expr) = lto_input_tree (ib, data_in); + DECL_CONTEXT (expr) = lto_input_tree (ib, data_in); + DECL_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in); +} + + +/* Read all pointer fields in the TS_DECL_COMMON structure of EXPR from + input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + DECL_SIZE (expr) = lto_input_tree (ib, data_in); + DECL_SIZE_UNIT (expr) = lto_input_tree (ib, data_in); + + if (TREE_CODE (expr) != FUNCTION_DECL) + DECL_INITIAL (expr) = lto_input_tree (ib, data_in); + + DECL_ATTRIBUTES (expr) = lto_input_tree (ib, data_in); + DECL_ABSTRACT_ORIGIN (expr) = lto_input_tree (ib, data_in); + + if (TREE_CODE (expr) == PARM_DECL) + TREE_CHAIN (expr) = lto_input_chain (ib, data_in); +} + + +/* Read all pointer fields in the TS_DECL_NON_COMMON structure of + EXPR from input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + if (TREE_CODE (expr) == FUNCTION_DECL) + { + DECL_ARGUMENTS (expr) = lto_input_tree (ib, data_in); + DECL_RESULT (expr) = lto_input_tree (ib, data_in); + } + DECL_VINDEX (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_DECL_WITH_VIS structure of EXPR + from input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + tree id; + + id = lto_input_tree (ib, data_in); + if (id) + { + gcc_assert (TREE_CODE (id) == IDENTIFIER_NODE); + SET_DECL_ASSEMBLER_NAME (expr, id); + } + + DECL_SECTION_NAME (expr) = lto_input_tree (ib, data_in); + DECL_COMDAT_GROUP (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_FIELD_DECL structure of EXPR from + input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_field_decl_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + DECL_FIELD_OFFSET (expr) = lto_input_tree (ib, data_in); + DECL_BIT_FIELD_TYPE (expr) = lto_input_tree (ib, data_in); + DECL_QUALIFIER (expr) = lto_input_tree (ib, data_in); + DECL_FIELD_BIT_OFFSET (expr) = lto_input_tree (ib, data_in); + DECL_FCONTEXT (expr) = lto_input_tree (ib, data_in); + TREE_CHAIN (expr) = lto_input_chain (ib, data_in); +} + + +/* Read all pointer fields in the TS_FUNCTION_DECL structure of EXPR + from input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + /* DECL_STRUCT_FUNCTION is handled by lto_input_function. FIXME lto, + maybe it should be handled here? */ + DECL_FUNCTION_PERSONALITY (expr) = lto_input_tree (ib, data_in); + DECL_FUNCTION_SPECIFIC_TARGET (expr) = lto_input_tree (ib, data_in); + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_TYPE structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_type_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + if (TREE_CODE (expr) == ENUMERAL_TYPE) + TYPE_VALUES (expr) = lto_input_tree (ib, data_in); + else if (TREE_CODE (expr) == ARRAY_TYPE) + TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in); + else if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE) + TYPE_FIELDS (expr) = lto_input_tree (ib, data_in); + else if (TREE_CODE (expr) == FUNCTION_TYPE || TREE_CODE (expr) == METHOD_TYPE) + TYPE_ARG_TYPES (expr) = lto_input_tree (ib, data_in); + else if (TREE_CODE (expr) == VECTOR_TYPE) + TYPE_DEBUG_REPRESENTATION_TYPE (expr) = lto_input_tree (ib, data_in); + + TYPE_SIZE (expr) = lto_input_tree (ib, data_in); + TYPE_SIZE_UNIT (expr) = lto_input_tree (ib, data_in); + TYPE_ATTRIBUTES (expr) = lto_input_tree (ib, data_in); + TYPE_NAME (expr) = lto_input_tree (ib, data_in); + /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO nor + TYPE_NEXT_PTR_TO or TYPE_NEXT_REF_TO. */ + if (!POINTER_TYPE_P (expr)) + TYPE_MINVAL (expr) = lto_input_tree (ib, data_in); + TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in); + TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in); + /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists + during fixup. */ + if (RECORD_OR_UNION_TYPE_P (expr)) + TYPE_BINFO (expr) = lto_input_tree (ib, data_in); + TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in); + TYPE_CANONICAL (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_LIST structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_list_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + TREE_PURPOSE (expr) = lto_input_tree (ib, data_in); + TREE_VALUE (expr) = lto_input_tree (ib, data_in); + TREE_CHAIN (expr) = lto_input_chain (ib, data_in); +} + + +/* Read all pointer fields in the TS_VEC structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_vec_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + int i; + + /* Note that TREE_VEC_LENGTH was read by lto_materialize_tree to + instantiate EXPR. */ + for (i = 0; i < TREE_VEC_LENGTH (expr); i++) + TREE_VEC_ELT (expr, i) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_EXP structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + + +static void +lto_input_ts_exp_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + int i, length; + location_t loc; + + length = lto_input_sleb128 (ib); + gcc_assert (length == TREE_OPERAND_LENGTH (expr)); + + for (i = 0; i < length; i++) + TREE_OPERAND (expr, i) = lto_input_tree (ib, data_in); + + loc = lto_input_location (ib, data_in); + SET_EXPR_LOCATION (expr, loc); + TREE_BLOCK (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_BLOCK structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_block_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + unsigned i, len; + + BLOCK_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in); + BLOCK_VARS (expr) = lto_input_chain (ib, data_in); + + len = lto_input_uleb128 (ib); + for (i = 0; i < len; i++) + { + tree t = lto_input_tree (ib, data_in); + VEC_safe_push (tree, gc, BLOCK_NONLOCALIZED_VARS (expr), t); + } + + BLOCK_SUPERCONTEXT (expr) = lto_input_tree (ib, data_in); + BLOCK_ABSTRACT_ORIGIN (expr) = lto_input_tree (ib, data_in); + BLOCK_FRAGMENT_ORIGIN (expr) = lto_input_tree (ib, data_in); + BLOCK_FRAGMENT_CHAIN (expr) = lto_input_tree (ib, data_in); + BLOCK_SUBBLOCKS (expr) = lto_input_chain (ib, data_in); +} + + +/* Read all pointer fields in the TS_BINFO structure of EXPR from input + block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + unsigned i, len; + tree t; + + /* Note that the number of slots in EXPR was read in + lto_materialize_tree when instantiating EXPR. However, the + vector is empty so we cannot rely on VEC_length to know how many + elements to read. So, this list is emitted as a 0-terminated + list on the writer side. */ + do + { + t = lto_input_tree (ib, data_in); + if (t) + VEC_quick_push (tree, BINFO_BASE_BINFOS (expr), t); + } + while (t); + + BINFO_OFFSET (expr) = lto_input_tree (ib, data_in); + BINFO_VTABLE (expr) = lto_input_tree (ib, data_in); + BINFO_VIRTUALS (expr) = lto_input_tree (ib, data_in); + BINFO_VPTR_FIELD (expr) = lto_input_tree (ib, data_in); + + len = lto_input_uleb128 (ib); + for (i = 0; i < len; i++) + { + tree a = lto_input_tree (ib, data_in); + VEC_safe_push (tree, gc, BINFO_BASE_ACCESSES (expr), a); + } + + BINFO_INHERITANCE_CHAIN (expr) = lto_input_tree (ib, data_in); + BINFO_SUBVTT_INDEX (expr) = lto_input_tree (ib, data_in); + BINFO_VPTR_INDEX (expr) = lto_input_tree (ib, data_in); +} + + +/* Read all pointer fields in the TS_CONSTRUCTOR structure of EXPR from + input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib, + struct data_in *data_in, tree expr) +{ + unsigned i, len; + + len = lto_input_uleb128 (ib); + for (i = 0; i < len; i++) + { + tree index, value; + + index = lto_input_tree (ib, data_in); + value = lto_input_tree (ib, data_in); + CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value); + } +} + + +/* Helper for lto_input_tree. Read all pointer fields in EXPR from + input block IB. DATA_IN contains tables and descriptors for the + file being read. */ + +static void +lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in, + tree expr) +{ + enum tree_code code; + + code = TREE_CODE (expr); + + if (CODE_CONTAINS_STRUCT (code, TS_COMMON)) + lto_input_ts_common_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) + lto_input_ts_vector_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX)) + lto_input_ts_complex_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) + lto_input_ts_decl_minimal_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + lto_input_ts_decl_common_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) + lto_input_ts_decl_non_common_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + lto_input_ts_decl_with_vis_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL)) + lto_input_ts_field_decl_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + lto_input_ts_function_decl_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE)) + lto_input_ts_type_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_LIST)) + lto_input_ts_list_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_VEC)) + lto_input_ts_vec_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_EXP)) + lto_input_ts_exp_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME)) + { + /* We only stream the version number of SSA names. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_BLOCK)) + lto_input_ts_block_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) + lto_input_ts_binfo_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST)) + { + /* This should only appear in GENERIC. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR)) + lto_input_ts_constructor_tree_pointers (ib, data_in, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE)) + { + /* This should only appear in High GIMPLE. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION)) + { + sorry ("optimization options not supported yet"); + } + + if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)) + { + sorry ("target optimization options not supported yet"); + } +} + + +/* Register DECL with the global symbol table and change its + name if necessary to avoid name clashes for static globals across + different files. */ + +static void +lto_register_var_decl_in_symtab (struct data_in *data_in, tree decl) +{ + /* Register symbols with file or global scope to mark what input + file has their definition. */ + if (decl_function_context (decl) == NULL_TREE) + { + /* Variable has file scope, not local. Need to ensure static variables + between different files don't clash unexpectedly. */ + if (!TREE_PUBLIC (decl)) + { + /* ??? We normally pre-mangle names before we serialize them + out. Here, in lto1, we do not know the language, and + thus cannot do the mangling again. Instead, we just + append a suffix to the mangled name. The resulting name, + however, is not a properly-formed mangled name, and will + confuse any attempt to unmangle it. */ + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + char *label; + + ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl)); + SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label)); + rest_of_decl_compilation (decl, 1, 0); + } + } + + /* If this variable has already been declared, queue the + declaration for merging. */ + if (TREE_PUBLIC (decl)) + { + int ix; + if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix)) + gcc_unreachable (); + lto_symtab_register_decl (decl, get_resolution (data_in, ix), + data_in->file_data); + } +} + + + +/* Register DECL with the global symbol table and change its + name if necessary to avoid name clashes for static globals across + different files. DATA_IN contains descriptors and tables for the + file being read. */ + +static void +lto_register_function_decl_in_symtab (struct data_in *data_in, tree decl) +{ + /* Need to ensure static entities between different files + don't clash unexpectedly. */ + if (!TREE_PUBLIC (decl)) + { + /* We must not use the DECL_ASSEMBLER_NAME macro here, as it + may set the assembler name where it was previously empty. */ + tree old_assembler_name = decl->decl_with_vis.assembler_name; + + /* FIXME lto: We normally pre-mangle names before we serialize + them out. Here, in lto1, we do not know the language, and + thus cannot do the mangling again. Instead, we just append a + suffix to the mangled name. The resulting name, however, is + not a properly-formed mangled name, and will confuse any + attempt to unmangle it. */ + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + char *label; + + ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl)); + SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label)); + + /* We may arrive here with the old assembler name not set + if the function body is not needed, e.g., it has been + inlined away and does not appear in the cgraph. */ + if (old_assembler_name) + { + tree new_assembler_name = DECL_ASSEMBLER_NAME (decl); + + /* Make the original assembler name available for later use. + We may have used it to indicate the section within its + object file where the function body may be found. + FIXME lto: Find a better way to maintain the function decl + to body section mapping so we don't need this hack. */ + lto_record_renamed_decl (data_in->file_data, + IDENTIFIER_POINTER (old_assembler_name), + IDENTIFIER_POINTER (new_assembler_name)); + + /* Also register the reverse mapping so that we can find the + new name given to an existing assembler name (used when + restoring alias pairs in input_constructors_or_inits. */ + lto_record_renamed_decl (data_in->file_data, + IDENTIFIER_POINTER (new_assembler_name), + IDENTIFIER_POINTER (old_assembler_name)); + } + } + + /* If this variable has already been declared, queue the + declaration for merging. */ + if (TREE_PUBLIC (decl) && !DECL_ABSTRACT (decl)) + { + int ix; + if (!lto_streamer_cache_lookup (data_in->reader_cache, decl, &ix)) + gcc_unreachable (); + lto_symtab_register_decl (decl, get_resolution (data_in, ix), + data_in->file_data); + } +} + + +/* Read an index IX from input block IB and return the tree node at + DATA_IN->FILE_DATA->GLOBALS_INDEX[IX]. */ + +static tree +lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in) +{ + HOST_WIDE_INT ix; + tree result; + enum LTO_tags expected_tag; + unsigned HOST_WIDE_INT orig_offset; + + ix = lto_input_sleb128 (ib); + expected_tag = (enum LTO_tags) lto_input_uleb128 (ib); + + orig_offset = lto_input_uleb128 (ib); + gcc_assert (orig_offset == (unsigned) orig_offset); + + result = lto_streamer_cache_get (data_in->reader_cache, ix); + if (result == NULL_TREE) + { + /* We have not yet read the cache slot IX. Go to the offset + in the stream where the physical tree node is, and materialize + it from there. */ + struct lto_input_block fwd_ib; + + /* If we are trying to go back in the stream, something is wrong. + We should've read the node at the earlier position already. */ + if (ib->p >= orig_offset) + internal_error ("bytecode stream: tried to jump backwards in the " + "stream"); + + LTO_INIT_INPUT_BLOCK (fwd_ib, ib->data, orig_offset, ib->len); + result = lto_input_tree (&fwd_ib, data_in); + } + + gcc_assert (result + && TREE_CODE (result) == lto_tag_to_tree_code (expected_tag)); + + return result; +} + + +/* Read a code and class from input block IB and return the + corresponding builtin. DATA_IN is as in lto_input_tree. */ + +static tree +lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in) +{ + enum built_in_class fclass; + enum built_in_function fcode; + const char *asmname; + tree result; + int ix; + + fclass = (enum built_in_class) lto_input_uleb128 (ib); + gcc_assert (fclass == BUILT_IN_NORMAL || fclass == BUILT_IN_MD); + + fcode = (enum built_in_function) lto_input_uleb128 (ib); + + ix = lto_input_sleb128 (ib); + gcc_assert (ix == (int) ix); + + if (fclass == BUILT_IN_NORMAL) + { + gcc_assert (fcode < END_BUILTINS); + result = built_in_decls[fcode]; + gcc_assert (result); + } + else if (fclass == BUILT_IN_MD) + { + result = targetm.builtin_decl (fcode, true); + if (!result || result == error_mark_node) + fatal_error ("target specific builtin not available"); + } + + asmname = input_string (data_in, ib); + if (asmname) + set_builtin_user_assembler_name (result, asmname); + + lto_streamer_cache_insert_at (data_in->reader_cache, result, ix); + + return result; +} + + +/* Read the physical representation of a tree node with tag TAG from + input block IB using the per-file context in DATA_IN. */ + +static tree +lto_read_tree (struct lto_input_block *ib, struct data_in *data_in, + enum LTO_tags tag) +{ + tree result; + char end_marker; + int ix; + + result = lto_materialize_tree (ib, data_in, tag, &ix); + + /* Read all the pointer fields in RESULT. */ + lto_input_tree_pointers (ib, data_in, result); + + /* We should never try to instantiate an MD or NORMAL builtin here. */ + if (TREE_CODE (result) == FUNCTION_DECL) + gcc_assert (!lto_stream_as_builtin_p (result)); + + if (TREE_CODE (result) == VAR_DECL) + lto_register_var_decl_in_symtab (data_in, result); + else if (TREE_CODE (result) == FUNCTION_DECL && !DECL_BUILT_IN (result)) + lto_register_function_decl_in_symtab (data_in, result); + + end_marker = lto_input_1_unsigned (ib); + +#ifdef LTO_STREAMER_DEBUG + /* Remove the mapping to RESULT's original address set by + lto_materialize_tree. */ + lto_orig_address_remove (result); +#endif + + return result; +} + + +/* Read and INTEGER_CST node from input block IB using the per-file + context in DATA_IN. */ + +static tree +lto_input_integer_cst (struct lto_input_block *ib, struct data_in *data_in) +{ + tree result, type; + HOST_WIDE_INT low, high; + bool overflow_p; + + type = lto_input_tree (ib, data_in); + overflow_p = (lto_input_1_unsigned (ib) != 0); + low = lto_input_uleb128 (ib); + high = lto_input_uleb128 (ib); + result = build_int_cst_wide (type, low, high); + + /* If the original constant had overflown, build a replica of RESULT to + avoid modifying the shared constant returned by build_int_cst_wide. */ + if (overflow_p) + { + result = copy_node (result); + TREE_OVERFLOW (result) = 1; + } + + return result; +} + + +/* Read a tree from input block IB using the per-file context in + DATA_IN. This context is used, for example, to resolve references + to previously read nodes. */ + +tree +lto_input_tree (struct lto_input_block *ib, struct data_in *data_in) +{ + enum LTO_tags tag; + tree result; + + tag = input_record_start (ib); + gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS); + + if (tag == LTO_null) + result = NULL_TREE; + else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref) + { + /* If TAG is a reference to an indexable tree, the next value + in IB is the index into the table where we expect to find + that tree. */ + result = lto_input_tree_ref (ib, data_in, cfun, tag); + } + else if (tag == LTO_tree_pickle_reference) + { + /* If TAG is a reference to a previously read tree, look it up in + the reader cache. */ + result = lto_get_pickled_tree (ib, data_in); + } + else if (tag == LTO_builtin_decl) + { + /* If we are going to read a built-in function, all we need is + the code and class. */ + result = lto_get_builtin_tree (ib, data_in); + } + else if (tag == lto_tree_code_to_tag (INTEGER_CST)) + { + /* For integer constants we only need the type and its hi/low + words. */ + result = lto_input_integer_cst (ib, data_in); + } + else + { + /* Otherwise, materialize a new node from IB. */ + result = lto_read_tree (ib, data_in, tag); + } + + return result; +} + + +/* Initialization for the LTO reader. */ + +void +lto_init_reader (void) +{ + lto_streamer_init (); + + memset (<o_stats, 0, sizeof (lto_stats)); + bitmap_obstack_initialize (NULL); + + file_name_hash_table = htab_create (37, hash_string_slot_node, + eq_string_slot_node, free); + + gimple_register_cfg_hooks (); +} + + +/* Create a new data_in object for FILE_DATA. STRINGS is the string + table to use with LEN strings. RESOLUTIONS is the vector of linker + resolutions (NULL if not using a linker plugin). */ + +struct data_in * +lto_data_in_create (struct lto_file_decl_data *file_data, const char *strings, + unsigned len, + VEC(ld_plugin_symbol_resolution_t,heap) *resolutions) +{ + struct data_in *data_in = XCNEW (struct data_in); + data_in->file_data = file_data; + data_in->strings = strings; + data_in->strings_len = len; + data_in->globals_resolution = resolutions; + data_in->reader_cache = lto_streamer_cache_create (); + + return data_in; +} + + +/* Remove DATA_IN. */ + +void +lto_data_in_delete (struct data_in *data_in) +{ + VEC_free (ld_plugin_symbol_resolution_t, heap, data_in->globals_resolution); + lto_streamer_cache_delete (data_in->reader_cache); + free (data_in->labels); + free (data_in); +} diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c new file mode 100644 index 00000000000..1ed1939b2b2 --- /dev/null +++ b/gcc/lto-streamer-out.c @@ -0,0 +1,2551 @@ +/* Write the GIMPLE representation to a file stream. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Kenneth Zadeck + Re-implemented 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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "tree.h" +#include "expr.h" +#include "flags.h" +#include "params.h" +#include "input.h" +#include "varray.h" +#include "hashtab.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "cgraph.h" +#include "function.h" +#include "ggc.h" +#include "diagnostic.h" +#include "except.h" +#include "vec.h" +#include "lto-symtab.h" +#include "lto-streamer.h" + + +struct string_slot +{ + const char *s; + int len; + unsigned int slot_num; +}; + + +/* Returns a hash code for P. */ + +static hashval_t +hash_string_slot_node (const void *p) +{ + const struct string_slot *ds = (const struct string_slot *) p; + return (hashval_t) htab_hash_string (ds->s); +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +eq_string_slot_node (const void *p1, const void *p2) +{ + const struct string_slot *ds1 = (const struct string_slot *) p1; + const struct string_slot *ds2 = (const struct string_slot *) p2; + + if (ds1->len == ds2->len) + { + int i; + for (i = 0; i < ds1->len; i++) + if (ds1->s[i] != ds2->s[i]) + return 0; + return 1; + } + + return 0; +} + + +/* Free the string slot pointed-to by P. */ + +static void +string_slot_free (void *p) +{ + struct string_slot *slot = (struct string_slot *) p; + free (CONST_CAST (void *, (const void *) slot->s)); + free (slot); +} + + +/* Clear the line info stored in DATA_IN. */ + +static void +clear_line_info (struct output_block *ob) +{ + ob->current_file = NULL; + ob->current_line = 0; + ob->current_col = 0; +} + + +/* Create the output block and return it. SECTION_TYPE is + LTO_section_function_body or LTO_static_initializer. */ + +struct output_block * +create_output_block (enum lto_section_type section_type) +{ + struct output_block *ob = XCNEW (struct output_block); + + ob->section_type = section_type; + ob->decl_state = lto_get_out_decl_state (); + ob->main_stream = XCNEW (struct lto_output_stream); + ob->string_stream = XCNEW (struct lto_output_stream); + ob->writer_cache = lto_streamer_cache_create (); + + if (section_type == LTO_section_function_body) + ob->cfg_stream = XCNEW (struct lto_output_stream); + + clear_line_info (ob); + + ob->string_hash_table = htab_create (37, hash_string_slot_node, + eq_string_slot_node, string_slot_free); + + return ob; +} + + +/* Destroy the output block OB. */ + +void +destroy_output_block (struct output_block *ob) +{ + enum lto_section_type section_type = ob->section_type; + + htab_delete (ob->string_hash_table); + + free (ob->main_stream); + free (ob->string_stream); + if (section_type == LTO_section_function_body) + free (ob->cfg_stream); + + lto_streamer_cache_delete (ob->writer_cache); + + free (ob); +} + + +/* Output bitpack BP to output stream S. */ + +void +lto_output_bitpack (struct lto_output_stream *s, struct bitpack_d *bp) +{ + unsigned i; + bitpack_word_t v; + + lto_output_uleb128_stream (s, VEC_length (bitpack_word_t, bp->values)); + for (i = 0; VEC_iterate (bitpack_word_t, bp->values, i, v); i++) + lto_output_uleb128_stream (s, v); +} + + +/* Output STRING of LEN characters to the string + table in OB. The string might or might not include a trailing '\0'. + Then put the index onto the INDEX_STREAM. */ + +static void +output_string_with_length (struct output_block *ob, + struct lto_output_stream *index_stream, + const char *s, + unsigned int len) +{ + struct string_slot **slot; + struct string_slot s_slot; + char *string = (char *) xmalloc (len + 1); + memcpy (string, s, len); + string[len] = '\0'; + + s_slot.s = string; + s_slot.len = len; + s_slot.slot_num = 0; + + slot = (struct string_slot **) htab_find_slot (ob->string_hash_table, + &s_slot, INSERT); + if (*slot == NULL) + { + struct lto_output_stream *string_stream = ob->string_stream; + unsigned int start = string_stream->total_size; + struct string_slot *new_slot + = (struct string_slot *) xmalloc (sizeof (struct string_slot)); + unsigned int i; + + new_slot->s = string; + new_slot->len = len; + new_slot->slot_num = start; + *slot = new_slot; + lto_output_uleb128_stream (index_stream, start); + lto_output_uleb128_stream (string_stream, len); + for (i = 0; i < len; i++) + lto_output_1_stream (string_stream, string[i]); + } + else + { + struct string_slot *old_slot = (struct string_slot *)*slot; + lto_output_uleb128_stream (index_stream, old_slot->slot_num); + free (string); + } +} + +/* Output the '\0' terminated STRING to the string + table in OB. Then put the index onto the INDEX_STREAM. */ + +static void +output_string (struct output_block *ob, + struct lto_output_stream *index_stream, + const char *string) +{ + if (string) + { + lto_output_uleb128_stream (index_stream, 0); + output_string_with_length (ob, index_stream, string, strlen (string) + 1); + } + else + lto_output_uleb128_stream (index_stream, 1); +} + + +/* Output the STRING constant to the string + table in OB. Then put the index onto the INDEX_STREAM. */ + +static void +output_string_cst (struct output_block *ob, + struct lto_output_stream *index_stream, + tree string) +{ + if (string) + { + lto_output_uleb128_stream (index_stream, 0); + output_string_with_length (ob, index_stream, + TREE_STRING_POINTER (string), + TREE_STRING_LENGTH (string)); + } + else + lto_output_uleb128_stream (index_stream, 1); +} + + +/* Output the identifier ID to the string + table in OB. Then put the index onto the INDEX_STREAM. */ + +static void +output_identifier (struct output_block *ob, + struct lto_output_stream *index_stream, + tree id) +{ + if (id) + { + lto_output_uleb128_stream (index_stream, 0); + output_string_with_length (ob, index_stream, + IDENTIFIER_POINTER (id), + IDENTIFIER_LENGTH (id)); + } + else + lto_output_uleb128_stream (index_stream, 1); +} + +/* Write a zero to the output stream. */ + +static void +output_zero (struct output_block *ob) +{ + lto_output_1_stream (ob->main_stream, 0); +} + + +/* Output an unsigned LEB128 quantity to OB->main_stream. */ + +static void +output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work) +{ + lto_output_uleb128_stream (ob->main_stream, work); +} + + +/* Output a signed LEB128 quantity to OB->main_stream. */ + +static void +output_sleb128 (struct output_block *ob, HOST_WIDE_INT work) +{ + lto_output_sleb128_stream (ob->main_stream, work); +} + + +/* Output the start of a record with TAG to output block OB. */ + +static void +output_record_start (struct output_block *ob, enum LTO_tags tag) +{ + /* Make sure TAG fits inside an unsigned int. */ + gcc_assert (tag == (enum LTO_tags) (unsigned) tag); + output_uleb128 (ob, tag); +} + + +/* Look up NODE in the type table and write the index for it to OB. */ + +static void +output_type_ref (struct output_block *ob, tree node) +{ + output_record_start (ob, LTO_type_ref); + lto_output_type_ref_index (ob->decl_state, ob->main_stream, node); +} + + +/* Pack all the non-pointer fields of the TS_BASE structure of + expression EXPR into bitpack BP. */ + +static void +pack_ts_base_value_fields (struct bitpack_d *bp, tree expr) +{ + bp_pack_value (bp, TREE_CODE (expr), 16); + if (!TYPE_P (expr)) + { + bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1); + bp_pack_value (bp, TREE_CONSTANT (expr), 1); + bp_pack_value (bp, TREE_READONLY (expr), 1); + + /* TREE_PUBLIC is used on types to indicate that the type + has a TYPE_CACHED_VALUES vector. This is not streamed out, + so we skip it here. */ + bp_pack_value (bp, TREE_PUBLIC (expr), 1); + } + bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1); + bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1); + if (DECL_P (expr)) + bp_pack_value (bp, DECL_UNSIGNED (expr), 1); + else if (TYPE_P (expr)) + bp_pack_value (bp, TYPE_UNSIGNED (expr), 1); + bp_pack_value (bp, TREE_ASM_WRITTEN (expr), 1); + bp_pack_value (bp, TREE_NO_WARNING (expr), 1); + bp_pack_value (bp, TREE_USED (expr), 1); + bp_pack_value (bp, TREE_NOTHROW (expr), 1); + bp_pack_value (bp, TREE_STATIC (expr), 1); + bp_pack_value (bp, TREE_PRIVATE (expr), 1); + bp_pack_value (bp, TREE_PROTECTED (expr), 1); + bp_pack_value (bp, TREE_DEPRECATED (expr), 1); + if (TYPE_P (expr)) + bp_pack_value (bp, TYPE_SATURATING (expr), 1); + if (TREE_CODE (expr) == SSA_NAME) + bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1); +} + + +/* Pack all the non-pointer fields of the TS_REAL_CST structure of + expression EXPR into bitpack BP. */ + +static void +pack_ts_real_cst_value_fields (struct bitpack_d *bp, tree expr) +{ + unsigned i; + REAL_VALUE_TYPE r; + + r = TREE_REAL_CST (expr); + bp_pack_value (bp, r.cl, 2); + bp_pack_value (bp, r.decimal, 1); + bp_pack_value (bp, r.sign, 1); + bp_pack_value (bp, r.signalling, 1); + bp_pack_value (bp, r.canonical, 1); + bp_pack_value (bp, r.uexp, EXP_BITS); + for (i = 0; i < SIGSZ; i++) + bp_pack_value (bp, r.sig[i], HOST_BITS_PER_LONG); +} + + +/* Pack all the non-pointer fields of the TS_FIXED_CST structure of + expression EXPR into bitpack BP. */ + +static void +pack_ts_fixed_cst_value_fields (struct bitpack_d *bp, tree expr) +{ + struct fixed_value fv = TREE_FIXED_CST (expr); + bp_pack_value (bp, fv.data.low, HOST_BITS_PER_WIDE_INT); + bp_pack_value (bp, fv.data.high, HOST_BITS_PER_WIDE_INT); +} + + +/* Pack all the non-pointer fields of the TS_DECL_COMMON structure + of expression EXPR into bitpack BP. */ + +static void +pack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr) +{ + bp_pack_value (bp, DECL_MODE (expr), 8); + bp_pack_value (bp, DECL_NONLOCAL (expr), 1); + bp_pack_value (bp, DECL_VIRTUAL_P (expr), 1); + bp_pack_value (bp, DECL_IGNORED_P (expr), 1); + bp_pack_value (bp, DECL_ABSTRACT (expr), 1); + bp_pack_value (bp, DECL_ARTIFICIAL (expr), 1); + bp_pack_value (bp, DECL_USER_ALIGN (expr), 1); + bp_pack_value (bp, DECL_PRESERVE_P (expr), 1); + bp_pack_value (bp, DECL_DEBUG_EXPR_IS_FROM (expr), 1); + bp_pack_value (bp, DECL_EXTERNAL (expr), 1); + bp_pack_value (bp, DECL_GIMPLE_REG_P (expr), 1); + bp_pack_value (bp, DECL_ALIGN (expr), HOST_BITS_PER_INT); + + if (TREE_CODE (expr) == LABEL_DECL) + { + /* Note that we do not write LABEL_DECL_UID. The reader will + always assume an initial value of -1 so that the + label_to_block_map is recreated by gimple_set_bb. */ + bp_pack_value (bp, DECL_ERROR_ISSUED (expr), 1); + bp_pack_value (bp, EH_LANDING_PAD_NR (expr), HOST_BITS_PER_INT); + } + + if (TREE_CODE (expr) == FIELD_DECL) + { + bp_pack_value (bp, DECL_PACKED (expr), 1); + bp_pack_value (bp, DECL_NONADDRESSABLE_P (expr), 1); + bp_pack_value (bp, DECL_OFFSET_ALIGN (expr), 8); + } + + if (TREE_CODE (expr) == RESULT_DECL + || TREE_CODE (expr) == PARM_DECL + || TREE_CODE (expr) == VAR_DECL) + { + bp_pack_value (bp, DECL_BY_REFERENCE (expr), 1); + if (TREE_CODE (expr) == VAR_DECL + || TREE_CODE (expr) == PARM_DECL) + bp_pack_value (bp, DECL_HAS_VALUE_EXPR_P (expr), 1); + bp_pack_value (bp, DECL_RESTRICTED_P (expr), 1); + } +} + + +/* Pack all the non-pointer fields of the TS_DECL_WRTL structure + of expression EXPR into bitpack BP. */ + +static void +pack_ts_decl_wrtl_value_fields (struct bitpack_d *bp, tree expr) +{ + bp_pack_value (bp, DECL_REGISTER (expr), 1); +} + + +/* Pack all the non-pointer fields of the TS_DECL_WITH_VIS structure + of expression EXPR into bitpack BP. */ + +static void +pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) +{ + bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1); + bp_pack_value (bp, DECL_COMMON (expr), 1); + bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1); + bp_pack_value (bp, DECL_WEAK (expr), 1); + bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr), 1); + bp_pack_value (bp, DECL_COMDAT (expr), 1); + bp_pack_value (bp, DECL_VISIBILITY (expr), 2); + bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr), 1); + + if (TREE_CODE (expr) == VAR_DECL) + { + bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1); + bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1); + bp_pack_value (bp, DECL_TLS_MODEL (expr), 3); + } + + if (VAR_OR_FUNCTION_DECL_P (expr)) + bp_pack_value (bp, DECL_INIT_PRIORITY (expr), HOST_BITS_PER_SHORT); +} + + +/* Pack all the non-pointer fields of the TS_FUNCTION_DECL structure + of expression EXPR into bitpack BP. */ + +static void +pack_ts_function_decl_value_fields (struct bitpack_d *bp, tree expr) +{ + /* For normal/md builtins we only write the class and code, so they + should never be handled here. */ + gcc_assert (!lto_stream_as_builtin_p (expr)); + + bp_pack_value (bp, DECL_FUNCTION_CODE (expr), 11); + bp_pack_value (bp, DECL_BUILT_IN_CLASS (expr), 2); + bp_pack_value (bp, DECL_STATIC_CONSTRUCTOR (expr), 1); + bp_pack_value (bp, DECL_STATIC_DESTRUCTOR (expr), 1); + bp_pack_value (bp, DECL_UNINLINABLE (expr), 1); + bp_pack_value (bp, DECL_POSSIBLY_INLINED (expr), 1); + bp_pack_value (bp, DECL_IS_NOVOPS (expr), 1); + bp_pack_value (bp, DECL_IS_RETURNS_TWICE (expr), 1); + bp_pack_value (bp, DECL_IS_MALLOC (expr), 1); + bp_pack_value (bp, DECL_IS_OPERATOR_NEW (expr), 1); + bp_pack_value (bp, DECL_DECLARED_INLINE_P (expr), 1); + bp_pack_value (bp, DECL_STATIC_CHAIN (expr), 1); + bp_pack_value (bp, DECL_NO_INLINE_WARNING_P (expr), 1); + bp_pack_value (bp, DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (expr), 1); + bp_pack_value (bp, DECL_NO_LIMIT_STACK (expr), 1); + bp_pack_value (bp, DECL_DISREGARD_INLINE_LIMITS (expr), 1); + bp_pack_value (bp, DECL_PURE_P (expr), 1); + bp_pack_value (bp, DECL_LOOPING_CONST_OR_PURE_P (expr), 1); +} + + +/* Pack all the non-pointer fields of the TS_TYPE structure + of expression EXPR into bitpack BP. */ + +static void +pack_ts_type_value_fields (struct bitpack_d *bp, tree expr) +{ + bp_pack_value (bp, TYPE_PRECISION (expr), 9); + bp_pack_value (bp, TYPE_MODE (expr), 7); + bp_pack_value (bp, TYPE_STRING_FLAG (expr), 1); + bp_pack_value (bp, TYPE_NO_FORCE_BLK (expr), 1); + bp_pack_value (bp, TYPE_NEEDS_CONSTRUCTING(expr), 1); + if (TREE_CODE (expr) == UNION_TYPE) + bp_pack_value (bp, TYPE_TRANSPARENT_UNION (expr), 1); + bp_pack_value (bp, TYPE_PACKED (expr), 1); + bp_pack_value (bp, TYPE_RESTRICT (expr), 1); + bp_pack_value (bp, TYPE_CONTAINS_PLACEHOLDER_INTERNAL (expr), 2); + bp_pack_value (bp, TYPE_USER_ALIGN (expr), 1); + bp_pack_value (bp, TYPE_READONLY (expr), 1); + bp_pack_value (bp, TYPE_ALIGN (expr), HOST_BITS_PER_INT); + bp_pack_value (bp, TYPE_ALIAS_SET (expr) == 0 ? 0 : -1, HOST_BITS_PER_INT); +} + + +/* Pack all the non-pointer fields of the TS_BLOCK structure + of expression EXPR into bitpack BP. */ + +static void +pack_ts_block_value_fields (struct bitpack_d *bp, tree expr) +{ + bp_pack_value (bp, BLOCK_ABSTRACT (expr), 1); + bp_pack_value (bp, BLOCK_NUMBER (expr), 31); +} + + +/* Pack all the non-pointer fields in EXPR into a bit pack. */ + +static struct bitpack_d * +pack_value_fields (tree expr) +{ + enum tree_code code; + struct bitpack_d *bp; + + code = TREE_CODE (expr); + bp = bitpack_create (); + + /* Note that all these functions are highly sensitive to changes in + the types and sizes of each of the fields being packed. */ + pack_ts_base_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST)) + pack_ts_real_cst_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_FIXED_CST)) + pack_ts_fixed_cst_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + pack_ts_decl_common_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) + pack_ts_decl_wrtl_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + pack_ts_decl_with_vis_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + pack_ts_function_decl_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE)) + pack_ts_type_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_BLOCK)) + pack_ts_block_value_fields (bp, expr); + + if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME)) + { + /* We only stream the version number of SSA names. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST)) + { + /* This is only used by GENERIC. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE)) + { + /* This is only used by High GIMPLE. */ + gcc_unreachable (); + } + + return bp; +} + + +/* Emit location LOC to output block OB. */ + +static void +lto_output_location (struct output_block *ob, location_t loc) +{ + expanded_location xloc; + + if (loc == UNKNOWN_LOCATION) + { + output_string (ob, ob->main_stream, NULL); + return; + } + + xloc = expand_location (loc); + + output_string (ob, ob->main_stream, xloc.file); + output_sleb128 (ob, xloc.line); + output_sleb128 (ob, xloc.column); + output_sleb128 (ob, xloc.sysp); + + ob->current_file = xloc.file; + ob->current_line = xloc.line; + ob->current_col = xloc.column; +} + + +/* Return true if tree node T is written to various tables. For these + nodes, we sometimes want to write their phyiscal representation + (via lto_output_tree), and sometimes we need to emit an index + reference into a table (via lto_output_tree_ref). */ + +static bool +tree_is_indexable (tree t) +{ + if (TREE_CODE (t) == PARM_DECL) + return false; + else if (TREE_CODE (t) == VAR_DECL && decl_function_context (t)) + return false; + else + return (TYPE_P (t) || DECL_P (t) || TREE_CODE (t) == SSA_NAME); +} + + +/* If EXPR is an indexable tree node, output a reference to it to + output block OB. Otherwise, output the physical representation of + EXPR to OB. */ + +static void +lto_output_tree_ref (struct output_block *ob, tree expr) +{ + enum tree_code code; + + if (expr == NULL_TREE) + { + output_zero (ob); + return; + } + + if (!tree_is_indexable (expr)) + { + /* Even though we are emitting the physical representation of + EXPR, its leaves must be emitted as references. */ + lto_output_tree (ob, expr, true); + return; + } + + if (TYPE_P (expr)) + { + output_type_ref (ob, expr); + return; + } + + code = TREE_CODE (expr); + switch (code) + { + case SSA_NAME: + output_record_start (ob, LTO_ssa_name_ref); + output_uleb128 (ob, SSA_NAME_VERSION (expr)); + break; + + case FIELD_DECL: + output_record_start (ob, LTO_field_decl_ref); + lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case FUNCTION_DECL: + output_record_start (ob, LTO_function_decl_ref); + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case VAR_DECL: + case DEBUG_EXPR_DECL: + gcc_assert (decl_function_context (expr) == NULL); + output_record_start (ob, LTO_global_decl_ref); + lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case CONST_DECL: + output_record_start (ob, LTO_const_decl_ref); + lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case IMPORTED_DECL: + gcc_assert (decl_function_context (expr) == NULL); + output_record_start (ob, LTO_imported_decl_ref); + lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case TYPE_DECL: + output_record_start (ob, LTO_type_decl_ref); + lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case NAMESPACE_DECL: + output_record_start (ob, LTO_namespace_decl_ref); + lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case LABEL_DECL: + output_record_start (ob, LTO_label_decl_ref); + lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + case RESULT_DECL: + output_record_start (ob, LTO_result_decl_ref); + lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr); + break; + + default: + /* No other node is indexable, so it should have been handled + by lto_output_tree. */ + gcc_unreachable (); + } +} + + +/* If REF_P is true, emit a reference to EXPR in output block OB, + otherwise emit the physical representation of EXPR in OB. */ + +static inline void +lto_output_tree_or_ref (struct output_block *ob, tree expr, bool ref_p) +{ + if (ref_p) + lto_output_tree_ref (ob, expr); + else + lto_output_tree (ob, expr, false); +} + + +/* Emit the chain of tree nodes starting at T. OB is the output block + to write to. REF_P is true if chain elements should be emitted + as references. */ + +static void +lto_output_chain (struct output_block *ob, tree t, bool ref_p) +{ + int i, count; + + count = list_length (t); + output_sleb128 (ob, count); + for (i = 0; i < count; i++) + { + tree saved_chain; + + /* Clear TREE_CHAIN to avoid blindly recursing into the rest + of the list. */ + saved_chain = TREE_CHAIN (t); + TREE_CHAIN (t) = NULL_TREE; + + lto_output_tree_or_ref (ob, t, ref_p); + + TREE_CHAIN (t) = saved_chain; + t = TREE_CHAIN (t); + } +} + + +/* Write all pointer fields in the TS_COMMON structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_common_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + lto_output_tree_or_ref (ob, TREE_TYPE (expr), ref_p); +} + + +/* Write all pointer fields in the TS_VECTOR structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_vector_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + lto_output_chain (ob, TREE_VECTOR_CST_ELTS (expr), ref_p); +} + + +/* Write all pointer fields in the TS_COMPLEX structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_complex_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + lto_output_tree_or_ref (ob, TREE_REALPART (expr), ref_p); + lto_output_tree_or_ref (ob, TREE_IMAGPART (expr), ref_p); +} + + +/* Write all pointer fields in the TS_DECL_MINIMAL structure of EXPR + to output block OB. If REF_P is true, write a reference to EXPR's + pointer fields. */ + +static void +lto_output_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + lto_output_tree_or_ref (ob, DECL_NAME (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_CONTEXT (expr), ref_p); + lto_output_location (ob, DECL_SOURCE_LOCATION (expr)); +} + + +/* Write all pointer fields in the TS_DECL_COMMON structure of EXPR to + output block OB. If REF_P is true, write a reference to EXPR's + pointer fields. */ + +static void +lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + lto_output_tree_or_ref (ob, DECL_SIZE (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p); + + if (TREE_CODE (expr) != FUNCTION_DECL) + lto_output_tree_or_ref (ob, DECL_INITIAL (expr), ref_p); + + lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_ABSTRACT_ORIGIN (expr), ref_p); + + if (TREE_CODE (expr) == PARM_DECL) + lto_output_chain (ob, TREE_CHAIN (expr), ref_p); +} + + +/* Write all pointer fields in the TS_DECL_NON_COMMON structure of + EXPR to output block OB. If REF_P is true, write a reference to EXPR's + pointer fields. */ + +static void +lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob, + tree expr, bool ref_p) +{ + if (TREE_CODE (expr) == FUNCTION_DECL) + { + /* DECL_SAVED_TREE holds the GENERIC representation for DECL. + At this point, it should not exist. Either because it was + converted to gimple or because DECL didn't have a GENERIC + representation in this TU. */ + gcc_assert (DECL_SAVED_TREE (expr) == NULL_TREE); + lto_output_tree_or_ref (ob, DECL_ARGUMENTS (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_RESULT (expr), ref_p); + } + lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p); +} + + +/* Write all pointer fields in the TS_DECL_WITH_VIS structure of EXPR + to output block OB. If REF_P is true, write a reference to EXPR's + pointer fields. */ + +static void +lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + /* Make sure we don't inadvertently set the assembler name. */ + if (DECL_ASSEMBLER_NAME_SET_P (expr)) + lto_output_tree_or_ref (ob, DECL_ASSEMBLER_NAME (expr), ref_p); + else + output_zero (ob); + + lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p); +} + + +/* Write all pointer fields in the TS_FIELD_DECL structure of EXPR to + output block OB. If REF_P is true, write a reference to EXPR's + pointer fields. */ + +static void +lto_output_ts_field_decl_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + lto_output_tree_or_ref (ob, DECL_FIELD_OFFSET (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_BIT_FIELD_TYPE (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_QUALIFIER (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_FCONTEXT (expr), ref_p); + lto_output_chain (ob, TREE_CHAIN (expr), ref_p); +} + + +/* Write all pointer fields in the TS_FUNCTION_DECL structure of EXPR + to output block OB. If REF_P is true, write a reference to EXPR's + pointer fields. */ + +static void +lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + /* DECL_STRUCT_FUNCTION is handled by lto_output_function. FIXME lto, + maybe it should be handled here? */ + lto_output_tree_or_ref (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p); + lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr), + ref_p); +} + + +/* Write all pointer fields in the TS_TYPE structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_type_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + if (TREE_CODE (expr) == ENUMERAL_TYPE) + lto_output_tree_or_ref (ob, TYPE_VALUES (expr), ref_p); + else if (TREE_CODE (expr) == ARRAY_TYPE) + lto_output_tree_or_ref (ob, TYPE_DOMAIN (expr), ref_p); + else if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE) + lto_output_tree_or_ref (ob, TYPE_FIELDS (expr), ref_p); + else if (TREE_CODE (expr) == FUNCTION_TYPE || TREE_CODE (expr) == METHOD_TYPE) + lto_output_tree_or_ref (ob, TYPE_ARG_TYPES (expr), ref_p); + else if (TREE_CODE (expr) == VECTOR_TYPE) + lto_output_tree_or_ref (ob, TYPE_DEBUG_REPRESENTATION_TYPE (expr), ref_p); + + lto_output_tree_or_ref (ob, TYPE_SIZE (expr), ref_p); + lto_output_tree_or_ref (ob, TYPE_SIZE_UNIT (expr), ref_p); + lto_output_tree_or_ref (ob, TYPE_ATTRIBUTES (expr), ref_p); + lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p); + /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO nor + TYPE_NEXT_PTR_TO or TYPE_NEXT_REF_TO. */ + if (!POINTER_TYPE_P (expr)) + lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p); + lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p); + lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p); + /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists + during fixup. */ + if (TREE_CODE (expr) == RECORD_TYPE || TREE_CODE (expr) == UNION_TYPE) + lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p); + lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p); + lto_output_tree_or_ref (ob, TYPE_CANONICAL (expr), ref_p); +} + + +/* Write all pointer fields in the TS_LIST structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_list_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + lto_output_tree_or_ref (ob, TREE_PURPOSE (expr), ref_p); + lto_output_tree_or_ref (ob, TREE_VALUE (expr), ref_p); + lto_output_chain (ob, TREE_CHAIN (expr), ref_p); +} + + +/* Write all pointer fields in the TS_VEC structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p) +{ + int i; + + /* Note that the number of slots for EXPR has already been emitted + in EXPR's header (see lto_output_tree_header). */ + for (i = 0; i < TREE_VEC_LENGTH (expr); i++) + lto_output_tree_or_ref (ob, TREE_VEC_ELT (expr, i), ref_p); +} + + +/* Write all pointer fields in the TS_EXP structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p) +{ + int i; + + output_sleb128 (ob, TREE_OPERAND_LENGTH (expr)); + for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++) + lto_output_tree_or_ref (ob, TREE_OPERAND (expr, i), ref_p); + lto_output_location (ob, EXPR_LOCATION (expr)); + lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p); +} + + +/* Write all pointer fields in the TS_BLOCK structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + unsigned i; + tree t; + + lto_output_location (ob, BLOCK_SOURCE_LOCATION (expr)); + lto_output_chain (ob, BLOCK_VARS (expr), ref_p); + + output_uleb128 (ob, VEC_length (tree, BLOCK_NONLOCALIZED_VARS (expr))); + for (i = 0; VEC_iterate (tree, BLOCK_NONLOCALIZED_VARS (expr), i, t); i++) + lto_output_tree_or_ref (ob, t, ref_p); + + lto_output_tree_or_ref (ob, BLOCK_SUPERCONTEXT (expr), ref_p); + lto_output_tree_or_ref (ob, BLOCK_ABSTRACT_ORIGIN (expr), ref_p); + lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p); + lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p); + lto_output_chain (ob, BLOCK_SUBBLOCKS (expr), ref_p); +} + + +/* Write all pointer fields in the TS_BINFO structure of EXPR to output + block OB. If REF_P is true, write a reference to EXPR's pointer + fields. */ + +static void +lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + unsigned i; + tree t; + + /* Note that the number of BINFO slots has already been emitted in + EXPR's header (see lto_output_tree_header) because this length + is needed to build the empty BINFO node on the reader side. */ + for (i = 0; VEC_iterate (tree, BINFO_BASE_BINFOS (expr), i, t); i++) + lto_output_tree_or_ref (ob, t, ref_p); + output_zero (ob); + + lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p); + lto_output_tree_or_ref (ob, BINFO_VTABLE (expr), ref_p); + lto_output_tree_or_ref (ob, BINFO_VIRTUALS (expr), ref_p); + lto_output_tree_or_ref (ob, BINFO_VPTR_FIELD (expr), ref_p); + + output_uleb128 (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr))); + for (i = 0; VEC_iterate (tree, BINFO_BASE_ACCESSES (expr), i, t); i++) + lto_output_tree_or_ref (ob, t, ref_p); + + lto_output_tree_or_ref (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p); + lto_output_tree_or_ref (ob, BINFO_SUBVTT_INDEX (expr), ref_p); + lto_output_tree_or_ref (ob, BINFO_VPTR_INDEX (expr), ref_p); +} + + +/* Write all pointer fields in the TS_CONSTRUCTOR structure of EXPR to + output block OB. If REF_P is true, write a reference to EXPR's + pointer fields. */ + +static void +lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr, + bool ref_p) +{ + unsigned i; + tree index, value; + + output_uleb128 (ob, CONSTRUCTOR_NELTS (expr)); + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, index, value) + { + lto_output_tree_or_ref (ob, index, ref_p); + lto_output_tree_or_ref (ob, value, ref_p); + } +} + + +/* Helper for lto_output_tree. Write all pointer fields in EXPR to output + block OB. If REF_P is true, the leaves of EXPR are emitted as + references. */ + +static void +lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p) +{ + enum tree_code code; + + code = TREE_CODE (expr); + + if (CODE_CONTAINS_STRUCT (code, TS_COMMON)) + lto_output_ts_common_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_VECTOR)) + lto_output_ts_vector_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_COMPLEX)) + lto_output_ts_complex_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_MINIMAL)) + lto_output_ts_decl_minimal_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) + lto_output_ts_decl_common_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) + lto_output_ts_decl_non_common_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) + lto_output_ts_decl_with_vis_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_FIELD_DECL)) + lto_output_ts_field_decl_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_FUNCTION_DECL)) + lto_output_ts_function_decl_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_TYPE)) + lto_output_ts_type_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_LIST)) + lto_output_ts_list_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_VEC)) + lto_output_ts_vec_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_EXP)) + lto_output_ts_exp_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME)) + { + /* We only stream the version number of SSA names. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_BLOCK)) + lto_output_ts_block_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) + lto_output_ts_binfo_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR)) + lto_output_ts_constructor_tree_pointers (ob, expr, ref_p); + + if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST)) + { + /* This should only appear in GENERIC. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE)) + { + /* This should only appear in High GIMPLE. */ + gcc_unreachable (); + } + + if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION)) + sorry ("gimple bytecode streams do not support the optimization attribute"); + + if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)) + sorry ("gimple bytecode streams do not support the target attribute"); +} + + +/* Emit header information for tree EXPR to output block OB. The header + contains everything needed to instantiate an empty skeleton for + EXPR on the reading side. IX is the index into the streamer cache + where EXPR is stored. REF_P is as in lto_output_tree. */ + +static void +lto_output_tree_header (struct output_block *ob, tree expr, int ix) +{ + enum LTO_tags tag; + enum tree_code code; + + /* We should not see any non-GIMPLE tree nodes here. */ + code = TREE_CODE (expr); + if (!lto_is_streamable (expr)) + internal_error ("tree code %qs is not supported in gimple streams", + tree_code_name[code]); + + /* The header of a tree node consists of its tag, the size of + the node, and any other information needed to instantiate + EXPR on the reading side (such as the number of slots in + variable sized nodes). */ + tag = lto_tree_code_to_tag (code); + output_record_start (ob, tag); + output_sleb128 (ob, ix); + + /* The following will cause bootstrap miscomparisons. Enable with care. */ +#ifdef LTO_STREAMER_DEBUG + /* This is used mainly for debugging purposes. When the reader + and the writer do not agree on a streamed node, the pointer + value for EXPR can be used to track down the differences in + the debugger. */ + gcc_assert ((HOST_WIDEST_INT) (intptr_t) expr == (intptr_t) expr); + output_sleb128 (ob, (HOST_WIDEST_INT) (intptr_t) expr); +#endif + + /* The text in strings and identifiers are completely emitted in + the header. */ + if (CODE_CONTAINS_STRUCT (code, TS_STRING)) + output_string_cst (ob, ob->main_stream, expr); + else if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER)) + output_identifier (ob, ob->main_stream, expr); + else if (CODE_CONTAINS_STRUCT (code, TS_VEC)) + output_sleb128 (ob, TREE_VEC_LENGTH (expr)); + else if (CODE_CONTAINS_STRUCT (code, TS_BINFO)) + output_uleb128 (ob, BINFO_N_BASE_BINFOS (expr)); +} + + +/* Write the code and class of builtin EXPR to output block OB. IX is + the index into the streamer cache where EXPR is stored.*/ + +static void +lto_output_builtin_tree (struct output_block *ob, tree expr, int ix) +{ + gcc_assert (lto_stream_as_builtin_p (expr)); + + if (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD + && !targetm.builtin_decl) + sorry ("gimple bytecode streams do not support machine specific builtin " + "functions on this target"); + + output_record_start (ob, LTO_builtin_decl); + output_uleb128 (ob, DECL_BUILT_IN_CLASS (expr)); + output_uleb128 (ob, DECL_FUNCTION_CODE (expr)); + output_sleb128 (ob, ix); + + if (DECL_ASSEMBLER_NAME_SET_P (expr)) + { + /* When the assembler name of a builtin gets a user name, + the new name is always prefixed with '*' by + set_builtin_user_assembler_name. So, to prevent the + reader side from adding a second '*', we omit it here. */ + const char *str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (expr)); + if (strlen (str) > 1 && str[0] == '*') + output_string (ob, ob->main_stream, &str[1]); + else + output_string (ob, ob->main_stream, NULL); + } + else + output_string (ob, ob->main_stream, NULL); +} + + +/* Write a physical representation of tree node EXPR to output block + OB. If REF_P is true, the leaves of EXPR are emitted as references + via lto_output_tree_ref. IX is the index into the streamer cache + where EXPR is stored. */ + +static void +lto_write_tree (struct output_block *ob, tree expr, bool ref_p, int ix) +{ + struct bitpack_d *bp; + + /* Write the header, containing everything needed to materialize + EXPR on the reading side. */ + lto_output_tree_header (ob, expr, ix); + + /* Pack all the non-pointer fields in EXPR into a bitpack and write + the resulting bitpack. */ + bp = pack_value_fields (expr); + lto_output_bitpack (ob->main_stream, bp); + bitpack_delete (bp); + + /* Write all the pointer fields in EXPR. */ + lto_output_tree_pointers (ob, expr, ref_p); + + /* Mark the end of EXPR. */ + output_zero (ob); +} + + +/* Emit the integer constant CST to output block OB. If REF_P is true, + CST's type will be emitted as a reference. */ + +static void +lto_output_integer_cst (struct output_block *ob, tree cst, bool ref_p) +{ + output_record_start (ob, lto_tree_code_to_tag (INTEGER_CST)); + lto_output_tree_or_ref (ob, TREE_TYPE (cst), ref_p); + lto_output_1_stream (ob->main_stream, TREE_OVERFLOW_P (cst)); + output_uleb128 (ob, TREE_INT_CST_LOW (cst)); + output_uleb128 (ob, TREE_INT_CST_HIGH (cst)); +} + + +/* Emit the physical representation of tree node EXPR to output block + OB. If REF_P is true, the leaves of EXPR are emitted as references + via lto_output_tree_ref. */ + +void +lto_output_tree (struct output_block *ob, tree expr, bool ref_p) +{ + int ix; + bool existed_p; + unsigned offset; + + if (expr == NULL_TREE) + { + output_zero (ob); + return; + } + + /* INTEGER_CST nodes are special because they need their original type + to be materialized by the reader (to implement TYPE_CACHED_VALUES). */ + if (TREE_CODE (expr) == INTEGER_CST) + { + lto_output_integer_cst (ob, expr, ref_p); + return; + } + + /* Determine the offset in the stream where EXPR will be written. + This is used when emitting pickle references so the reader knows + where to reconstruct the pickled object from. This allows + circular and forward references within the same stream. */ + offset = ob->main_stream->total_size; + + existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix, &offset); + if (existed_p) + { + /* If a node has already been streamed out, make sure that + we don't write it more than once. Otherwise, the reader + will instantiate two different nodes for the same object. */ + output_record_start (ob, LTO_tree_pickle_reference); + output_sleb128 (ob, ix); + output_uleb128 (ob, lto_tree_code_to_tag (TREE_CODE (expr))); + output_uleb128 (ob, offset); + } + else if (lto_stream_as_builtin_p (expr)) + { + /* MD and NORMAL builtins do not need to be written out + completely as they are always instantiated by the + compiler on startup. The only builtins that need to + be written out are BUILT_IN_FRONTEND. For all other + builtins, we simply write the class and code. */ + lto_output_builtin_tree (ob, expr, ix); + } + else + { + /* This is the first time we see EXPR, write its fields + to OB. */ + lto_write_tree (ob, expr, ref_p, ix); + } +} + + +/* Output to OB a list of try/catch handlers starting with FIRST. */ + +static void +output_eh_try_list (struct output_block *ob, eh_catch first) +{ + eh_catch n; + + for (n = first; n; n = n->next_catch) + { + output_record_start (ob, LTO_eh_catch); + lto_output_tree_ref (ob, n->type_list); + lto_output_tree_ref (ob, n->filter_list); + lto_output_tree_ref (ob, n->label); + } + + output_zero (ob); +} + + +/* Output EH region R in function FN to OB. CURR_RN is the slot index + that is being emitted in FN->EH->REGION_ARRAY. This is used to + detect EH region sharing. */ + +static void +output_eh_region (struct output_block *ob, eh_region r) +{ + enum LTO_tags tag; + + if (r == NULL) + { + output_zero (ob); + return; + } + + if (r->type == ERT_CLEANUP) + tag = LTO_ert_cleanup; + else if (r->type == ERT_TRY) + tag = LTO_ert_try; + else if (r->type == ERT_ALLOWED_EXCEPTIONS) + tag = LTO_ert_allowed_exceptions; + else if (r->type == ERT_MUST_NOT_THROW) + tag = LTO_ert_must_not_throw; + else + gcc_unreachable (); + + output_record_start (ob, tag); + output_sleb128 (ob, r->index); + + if (r->outer) + output_sleb128 (ob, r->outer->index); + else + output_zero (ob); + + if (r->inner) + output_sleb128 (ob, r->inner->index); + else + output_zero (ob); + + if (r->next_peer) + output_sleb128 (ob, r->next_peer->index); + else + output_zero (ob); + + if (r->type == ERT_TRY) + { + output_eh_try_list (ob, r->u.eh_try.first_catch); + } + else if (r->type == ERT_ALLOWED_EXCEPTIONS) + { + lto_output_tree_ref (ob, r->u.allowed.type_list); + lto_output_tree_ref (ob, r->u.allowed.label); + output_uleb128 (ob, r->u.allowed.filter); + } + else if (r->type == ERT_MUST_NOT_THROW) + { + lto_output_tree_ref (ob, r->u.must_not_throw.failure_decl); + lto_output_location (ob, r->u.must_not_throw.failure_loc); + } + + if (r->landing_pads) + output_sleb128 (ob, r->landing_pads->index); + else + output_zero (ob); +} + + +/* Output landing pad LP to OB. */ + +static void +output_eh_lp (struct output_block *ob, eh_landing_pad lp) +{ + if (lp == NULL) + { + output_zero (ob); + return; + } + + output_record_start (ob, LTO_eh_landing_pad); + output_sleb128 (ob, lp->index); + if (lp->next_lp) + output_sleb128 (ob, lp->next_lp->index); + else + output_zero (ob); + + if (lp->region) + output_sleb128 (ob, lp->region->index); + else + output_zero (ob); + + lto_output_tree_ref (ob, lp->post_landing_pad); +} + + +/* Output the existing eh_table to OB. */ + +static void +output_eh_regions (struct output_block *ob, struct function *fn) +{ + if (fn->eh && fn->eh->region_tree) + { + unsigned i; + eh_region eh; + eh_landing_pad lp; + tree ttype; + + output_record_start (ob, LTO_eh_table); + + /* Emit the index of the root of the EH region tree. */ + output_sleb128 (ob, fn->eh->region_tree->index); + + /* Emit all the EH regions in the region array. */ + output_sleb128 (ob, VEC_length (eh_region, fn->eh->region_array)); + for (i = 0; VEC_iterate (eh_region, fn->eh->region_array, i, eh); i++) + output_eh_region (ob, eh); + + /* Emit all landing pads. */ + output_sleb128 (ob, VEC_length (eh_landing_pad, fn->eh->lp_array)); + for (i = 0; VEC_iterate (eh_landing_pad, fn->eh->lp_array, i, lp); i++) + output_eh_lp (ob, lp); + + /* Emit all the runtime type data. */ + output_sleb128 (ob, VEC_length (tree, fn->eh->ttype_data)); + for (i = 0; VEC_iterate (tree, fn->eh->ttype_data, i, ttype); i++) + lto_output_tree_ref (ob, ttype); + + /* Emit the table of action chains. */ + if (targetm.arm_eabi_unwinder) + { + tree t; + output_sleb128 (ob, VEC_length (tree, fn->eh->ehspec_data.arm_eabi)); + for (i = 0; + VEC_iterate (tree, fn->eh->ehspec_data.arm_eabi, i, t); + i++) + lto_output_tree_ref (ob, t); + } + else + { + uchar c; + output_sleb128 (ob, VEC_length (uchar, fn->eh->ehspec_data.other)); + for (i = 0; VEC_iterate (uchar, fn->eh->ehspec_data.other, i, c); i++) + lto_output_1_stream (ob->main_stream, c); + } + } + + /* The 0 either terminates the record or indicates that there are no + eh_records at all. */ + output_zero (ob); +} + + +/* Output all of the active ssa names to the ssa_names stream. */ + +static void +output_ssa_names (struct output_block *ob, struct function *fn) +{ + unsigned int i, len; + + len = VEC_length (tree, SSANAMES (fn)); + output_uleb128 (ob, len); + + for (i = 1; i < len; i++) + { + tree ptr = VEC_index (tree, SSANAMES (fn), i); + + if (ptr == NULL_TREE + || SSA_NAME_IN_FREE_LIST (ptr) + || !is_gimple_reg (ptr)) + continue; + + output_uleb128 (ob, i); + lto_output_1_stream (ob->main_stream, SSA_NAME_IS_DEFAULT_DEF (ptr)); + lto_output_tree_ref (ob, SSA_NAME_VAR (ptr)); + } + + output_zero (ob); +} + + +/* Output the cfg. */ + +static void +output_cfg (struct output_block *ob, struct function *fn) +{ + struct lto_output_stream *tmp_stream = ob->main_stream; + basic_block bb; + + ob->main_stream = ob->cfg_stream; + + output_uleb128 (ob, profile_status_for_function (fn)); + + /* Output the number of the highest basic block. */ + output_uleb128 (ob, last_basic_block_for_function (fn)); + + FOR_ALL_BB_FN (bb, fn) + { + edge_iterator ei; + edge e; + + output_sleb128 (ob, bb->index); + + /* Output the successors and the edge flags. */ + output_uleb128 (ob, EDGE_COUNT (bb->succs)); + FOR_EACH_EDGE (e, ei, bb->succs) + { + output_uleb128 (ob, e->dest->index); + output_sleb128 (ob, e->probability); + output_sleb128 (ob, e->count); + output_uleb128 (ob, e->flags); + } + } + + output_sleb128 (ob, -1); + + bb = ENTRY_BLOCK_PTR; + while (bb->next_bb) + { + output_sleb128 (ob, bb->next_bb->index); + bb = bb->next_bb; + } + + output_sleb128 (ob, -1); + + ob->main_stream = tmp_stream; +} + + +/* Output PHI function PHI to the main stream in OB. */ + +static void +output_phi (struct output_block *ob, gimple phi) +{ + unsigned i, len = gimple_phi_num_args (phi); + + output_record_start (ob, lto_gimple_code_to_tag (GIMPLE_PHI)); + output_uleb128 (ob, SSA_NAME_VERSION (PHI_RESULT (phi))); + + for (i = 0; i < len; i++) + { + lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i)); + output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index); + lto_output_location (ob, gimple_phi_arg_location (phi, i)); + } +} + + +/* Emit statement STMT on the main stream of output block OB. */ + +static void +output_gimple_stmt (struct output_block *ob, gimple stmt) +{ + unsigned i; + enum gimple_code code; + enum LTO_tags tag; + struct bitpack_d *bp; + + /* Emit identifying tag. */ + code = gimple_code (stmt); + tag = lto_gimple_code_to_tag (code); + output_record_start (ob, tag); + + /* Emit the tuple header. */ + bp = bitpack_create (); + bp_pack_value (bp, gimple_num_ops (stmt), sizeof (unsigned) * 8); + bp_pack_value (bp, gimple_no_warning_p (stmt), 1); + if (is_gimple_assign (stmt)) + bp_pack_value (bp, gimple_assign_nontemporal_move_p (stmt), 1); + bp_pack_value (bp, gimple_has_volatile_ops (stmt), 1); + bp_pack_value (bp, stmt->gsbase.subcode, 16); + lto_output_bitpack (ob->main_stream, bp); + bitpack_delete (bp); + + /* Emit location information for the statement. */ + lto_output_location (ob, gimple_location (stmt)); + + /* Emit the lexical block holding STMT. */ + lto_output_tree (ob, gimple_block (stmt), true); + + /* Emit the operands. */ + switch (gimple_code (stmt)) + { + case GIMPLE_RESX: + output_sleb128 (ob, gimple_resx_region (stmt)); + break; + + case GIMPLE_EH_MUST_NOT_THROW: + lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt)); + break; + + case GIMPLE_EH_DISPATCH: + output_sleb128 (ob, gimple_eh_dispatch_region (stmt)); + break; + + case GIMPLE_ASM: + lto_output_uleb128_stream (ob->main_stream, gimple_asm_ninputs (stmt)); + lto_output_uleb128_stream (ob->main_stream, gimple_asm_noutputs (stmt)); + lto_output_uleb128_stream (ob->main_stream, gimple_asm_nclobbers (stmt)); + output_string (ob, ob->main_stream, gimple_asm_string (stmt)); + /* Fallthru */ + + case GIMPLE_ASSIGN: + case GIMPLE_CALL: + case GIMPLE_RETURN: + case GIMPLE_SWITCH: + case GIMPLE_LABEL: + case GIMPLE_COND: + case GIMPLE_GOTO: + case GIMPLE_DEBUG: + for (i = 0; i < gimple_num_ops (stmt); i++) + { + tree op = gimple_op (stmt, i); + lto_output_tree_ref (ob, op); + } + break; + + case GIMPLE_NOP: + case GIMPLE_PREDICT: + break; + + default: + gcc_unreachable (); + } +} + + +/* Output a basic block BB to the main stream in OB for this FN. */ + +static void +output_bb (struct output_block *ob, basic_block bb, struct function *fn) +{ + gimple_stmt_iterator bsi = gsi_start_bb (bb); + + output_record_start (ob, + (!gsi_end_p (bsi)) || phi_nodes (bb) + ? LTO_bb1 + : LTO_bb0); + + output_uleb128 (ob, bb->index); + output_sleb128 (ob, bb->count); + output_sleb128 (ob, bb->loop_depth); + output_sleb128 (ob, bb->frequency); + output_sleb128 (ob, bb->flags); + + if (!gsi_end_p (bsi) || phi_nodes (bb)) + { + /* Output the statements. The list of statements is terminated + with a zero. */ + for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) + { + int region; + gimple stmt = gsi_stmt (bsi); + + output_gimple_stmt (ob, stmt); + + /* Emit the EH region holding STMT. */ + region = lookup_stmt_eh_lp_fn (fn, stmt); + if (region != 0) + { + output_record_start (ob, LTO_eh_region); + output_sleb128 (ob, region); + } + else + output_zero (ob); + } + + output_zero (ob); + + for (bsi = gsi_start_phis (bb); !gsi_end_p (bsi); gsi_next (&bsi)) + { + gimple phi = gsi_stmt (bsi); + + /* Only emit PHIs for gimple registers. PHI nodes for .MEM + will be filled in on reading when the SSA form is + updated. */ + if (is_gimple_reg (gimple_phi_result (phi))) + output_phi (ob, phi); + } + + output_zero (ob); + } +} + +/* Create the header in the file using OB. If the section type is for + a function, set FN to the decl for that function. */ + +void +produce_asm (struct output_block *ob, tree fn) +{ + enum lto_section_type section_type = ob->section_type; + struct lto_function_header header; + char *section_name; + struct lto_output_stream *header_stream; + + if (section_type == LTO_section_function_body) + { + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn)); + section_name = lto_get_section_name (section_type, name); + } + else + section_name = lto_get_section_name (section_type, NULL); + + lto_begin_section (section_name, !flag_wpa); + free (section_name); + + /* The entire header is stream computed here. */ + memset (&header, 0, sizeof (struct lto_function_header)); + + /* Write the header. */ + header.lto_header.major_version = LTO_major_version; + header.lto_header.minor_version = LTO_minor_version; + header.lto_header.section_type = section_type; + + header.compressed_size = 0; + + if (section_type == LTO_section_function_body) + header.cfg_size = ob->cfg_stream->total_size; + header.main_size = ob->main_stream->total_size; + header.string_size = ob->string_stream->total_size; + + header_stream = XCNEW (struct lto_output_stream); + lto_output_data_stream (header_stream, &header, sizeof header); + lto_write_stream (header_stream); + free (header_stream); + + /* Put all of the gimple and the string table out the asm file as a + block of text. */ + if (section_type == LTO_section_function_body) + lto_write_stream (ob->cfg_stream); + lto_write_stream (ob->main_stream); + lto_write_stream (ob->string_stream); + + lto_end_section (); +} + + +/* Output the body of function NODE->DECL. */ + +static void +output_function (struct cgraph_node *node) +{ + struct bitpack_d *bp; + tree function; + struct function *fn; + basic_block bb; + struct output_block *ob; + + function = node->decl; + fn = DECL_STRUCT_FUNCTION (function); + ob = create_output_block (LTO_section_function_body); + + clear_line_info (ob); + ob->cgraph_node = node; + + gcc_assert (current_function_decl == NULL_TREE && cfun == NULL); + + /* Set current_function_decl and cfun. */ + current_function_decl = function; + push_cfun (fn); + + /* Make string 0 be a NULL string. */ + lto_output_1_stream (ob->string_stream, 0); + + output_record_start (ob, LTO_function); + + /* Write all the attributes for FN. */ + bp = bitpack_create (); + bp_pack_value (bp, fn->is_thunk, 1); + bp_pack_value (bp, fn->has_local_explicit_reg_vars, 1); + bp_pack_value (bp, fn->after_tree_profile, 1); + bp_pack_value (bp, fn->returns_pcc_struct, 1); + bp_pack_value (bp, fn->returns_struct, 1); + bp_pack_value (bp, fn->always_inline_functions_inlined, 1); + bp_pack_value (bp, fn->after_inlining, 1); + bp_pack_value (bp, fn->dont_save_pending_sizes_p, 1); + bp_pack_value (bp, fn->stdarg, 1); + bp_pack_value (bp, fn->has_nonlocal_label, 1); + bp_pack_value (bp, fn->calls_alloca, 1); + bp_pack_value (bp, fn->calls_setjmp, 1); + bp_pack_value (bp, fn->function_frequency, 2); + bp_pack_value (bp, fn->va_list_fpr_size, 8); + bp_pack_value (bp, fn->va_list_gpr_size, 8); + lto_output_bitpack (ob->main_stream, bp); + bitpack_delete (bp); + + /* Output the static chain and non-local goto save area. */ + lto_output_tree_ref (ob, fn->static_chain_decl); + lto_output_tree_ref (ob, fn->nonlocal_goto_save_area); + + /* Output all the local variables in the function. */ + lto_output_tree_ref (ob, fn->local_decls); + + /* Output all the SSA names used in the function. */ + output_ssa_names (ob, fn); + + /* Output any exception handling regions. */ + output_eh_regions (ob, fn); + + /* Output DECL_INITIAL for the function, which contains the tree of + lexical scopes. */ + lto_output_tree (ob, DECL_INITIAL (function), true); + + /* Output the head of the arguments list. */ + lto_output_tree_ref (ob, DECL_ARGUMENTS (function)); + + /* We will renumber the statements. The code that does this uses + the same ordering that we use for serializing them so we can use + the same code on the other end and not have to write out the + statement numbers. */ + renumber_gimple_stmt_uids (); + + /* Output the code for the function. */ + FOR_ALL_BB_FN (bb, fn) + output_bb (ob, bb, fn); + + /* The terminator for this function. */ + output_zero (ob); + + output_cfg (ob, fn); + + /* Create a section to hold the pickled output of this function. */ + produce_asm (ob, function); + + destroy_output_block (ob); + + current_function_decl = NULL; + pop_cfun (); +} + + +/* Return true if alias pair P belongs to the set of cgraph nodes in + SET. If P is a an alias for a VAR_DECL, it can always be emitted. + However, for FUNCTION_DECL aliases, we should only output the pair + if it belongs to a function whose cgraph node is in SET. + Otherwise, the LTRANS phase will get into trouble when finalizing + aliases because the alias will refer to a function not defined in + the file processed by LTRANS. */ + +static bool +output_alias_pair_p (alias_pair *p, cgraph_node_set set) +{ + cgraph_node_set_iterator csi; + struct cgraph_node *target_node; + + /* Always emit VAR_DECLs. FIXME lto, we should probably only emit + those VAR_DECLs that are instantiated in this file partition, but + we have no easy way of knowing this based on SET. */ + if (TREE_CODE (p->decl) == VAR_DECL) + return true; + + /* Check if the assembler name for P->TARGET has its cgraph node in SET. */ + gcc_assert (TREE_CODE (p->decl) == FUNCTION_DECL); + target_node = cgraph_node_for_asm (p->target); + csi = cgraph_node_set_find (set, target_node); + return (!csi_end_p (csi)); +} + + +/* Output any unreferenced global symbol defined in SET, alias pairs + and labels. */ + +static void +output_unreferenced_globals (cgraph_node_set set) +{ + struct output_block *ob; + alias_pair *p; + unsigned i; + struct varpool_node *vnode; + + ob = create_output_block (LTO_section_static_initializer); + ob->cgraph_node = NULL; + + clear_line_info (ob); + + /* Make string 0 be a NULL string. */ + lto_output_1_stream (ob->string_stream, 0); + + /* Emit references for all the global symbols. If a global symbol + was never referenced in any of the functions of this file, it + would not be emitted otherwise. This will result in unreferenced + symbols at link time if a file defines a global symbol but + never references it. */ + FOR_EACH_STATIC_VARIABLE (vnode) + { + tree var = vnode->decl; + + if (TREE_CODE (var) == VAR_DECL && TREE_PUBLIC (var)) + lto_output_tree_ref (ob, var); + } + + output_zero (ob); + + /* Emit the alias pairs for the nodes in SET. */ + for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++) + { + if (output_alias_pair_p (p, set)) + { + lto_output_tree_ref (ob, p->decl); + lto_output_tree_ref (ob, p->target); + } + } + + output_zero (ob); + + produce_asm (ob, NULL); + destroy_output_block (ob); +} + + +/* Copy the function body of NODE without deserializing. */ + +static void +copy_function (struct cgraph_node *node) +{ + tree function = node->decl; + struct lto_file_decl_data *file_data = node->local.lto_file_data; + struct lto_output_stream *output_stream = XCNEW (struct lto_output_stream); + const char *data; + size_t len; + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)); + char *section_name = + lto_get_section_name (LTO_section_function_body, name); + size_t i, j; + struct lto_in_decl_state *in_state; + struct lto_out_decl_state *out_state = lto_get_out_decl_state (); + + lto_begin_section (section_name, !flag_wpa); + free (section_name); + + /* We may have renamed the declaration, e.g., a static function. */ + name = lto_get_decl_name_mapping (file_data, name); + + data = lto_get_section_data (file_data, LTO_section_function_body, + name, &len); + gcc_assert (data); + + /* Do a bit copy of the function body. */ + lto_output_data_stream (output_stream, data, len); + lto_write_stream (output_stream); + + /* Copy decls. */ + in_state = + lto_get_function_in_decl_state (node->local.lto_file_data, function); + gcc_assert (in_state); + + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + { + size_t n = in_state->streams[i].size; + tree *trees = in_state->streams[i].trees; + struct lto_tree_ref_encoder *encoder = &(out_state->streams[i]); + + /* The out state must have the same indices and the in state. + So just copy the vector. All the encoders in the in state + must be empty where we reach here. */ + gcc_assert (lto_tree_ref_encoder_size (encoder) == 0); + for (j = 0; j < n; j++) + VEC_safe_push (tree, heap, encoder->trees, trees[j]); + encoder->next_index = n; + } + + lto_free_section_data (file_data, LTO_section_function_body, name, + data, len); + free (output_stream); + lto_end_section (); +} + + +/* Initialize the LTO writer. */ + +static void +lto_writer_init (void) +{ + lto_streamer_init (); +} + + +/* Main entry point from the pass manager. */ + +static void +lto_output (cgraph_node_set set) +{ + struct cgraph_node *node; + struct lto_out_decl_state *decl_state; + cgraph_node_set_iterator csi; + bitmap output = lto_bitmap_alloc (); + + lto_writer_init (); + + /* Process only the functions with bodies. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (node->analyzed && !bitmap_bit_p (output, DECL_UID (node->decl))) + { + bitmap_set_bit (output, DECL_UID (node->decl)); + decl_state = lto_new_out_decl_state (); + lto_push_out_decl_state (decl_state); + if (!flag_wpa) + output_function (node); + else + copy_function (node); + gcc_assert (lto_get_out_decl_state () == decl_state); + lto_pop_out_decl_state (); + lto_record_function_out_decl_state (node->decl, decl_state); + } + } + + /* Emit the callgraph after emitting function bodies. This needs to + be done now to make sure that all the statements in every function + have been renumbered so that edges can be associated with call + statements using the statement UIDs. */ + output_cgraph (set); + + lto_bitmap_free (output); +} + +struct ipa_opt_pass_d pass_ipa_lto_gimple_out = +{ + { + IPA_PASS, + "lto_gimple_out", /* name */ + gate_lto_out, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_IPA_LTO_GIMPLE_IO, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ + }, + NULL, /* generate_summary */ + lto_output, /* write_summary */ + NULL, /* read_summary */ + NULL, /* function_read_summary */ + 0, /* TODOs */ + NULL, /* function_transform */ + NULL /* variable_transform */ +}; + + +/* Write each node in encoded by ENCODER to OB, as well as those reachable + from it and required for correct representation of its semantics. + Each node in ENCODER must be a global declaration or a type. A node + is written only once, even if it appears multiple times in the + vector. Certain transitively-reachable nodes, such as those + representing expressions, may be duplicated, but such nodes + must not appear in ENCODER itself. */ + +static void +write_global_stream (struct output_block *ob, + struct lto_tree_ref_encoder *encoder) +{ + tree t; + size_t index; + const size_t size = lto_tree_ref_encoder_size (encoder); + + for (index = 0; index < size; index++) + { + t = lto_tree_ref_encoder_get_tree (encoder, index); + if (!lto_streamer_cache_lookup (ob->writer_cache, t, NULL)) + { + if (flag_wpa) + { + /* In WPA we should not emit multiple definitions of the + same symbol to all the files in the link set. If + T had already been emitted as the pervailing definition + in one file, emit it as an external reference in the + others. */ + /* FIXME lto. We should check if T belongs to the + file we are writing to. */ + if (TREE_CODE (t) == VAR_DECL + && TREE_PUBLIC (t) + && !DECL_EXTERNAL (t)) + { + /* FIXME lto. Make DECLS_ALREADY_EMITTED an argument + to this function so it can be freed up afterwards. + Alternately, assign global symbols to cgraph + node sets. */ + static struct pointer_set_t *decls_already_emitted = NULL; + + if (decls_already_emitted == NULL) + decls_already_emitted = pointer_set_create (); + + if (pointer_set_insert (decls_already_emitted, t)) + make_decl_one_only (t, DECL_ASSEMBLER_NAME (t)); + } + } + + lto_output_tree (ob, t, false); + } + } +} + + +/* Write a sequence of indices into the globals vector corresponding + to the trees in ENCODER. These are used by the reader to map the + indices used to refer to global entities within function bodies to + their referents. */ + +static void +write_global_references (struct output_block *ob, + struct lto_output_stream *ref_stream, + struct lto_tree_ref_encoder *encoder) +{ + tree t; + int32_t index; + const int32_t size = lto_tree_ref_encoder_size (encoder); + + /* Write size as 32-bit unsigned. */ + lto_output_data_stream (ref_stream, &size, sizeof (int32_t)); + + for (index = 0; index < size; index++) + { + int32_t slot_num; + + t = lto_tree_ref_encoder_get_tree (encoder, index); + lto_streamer_cache_lookup (ob->writer_cache, t, &slot_num); + gcc_assert (slot_num >= 0); + lto_output_data_stream (ref_stream, &slot_num, sizeof slot_num); + } +} + + +/* Write all the streams in an lto_out_decl_state STATE using + output block OB and output stream OUT_STREAM. */ + +static void +lto_output_decl_state_streams (struct output_block *ob, + struct lto_out_decl_state *state) +{ + int i; + + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + write_global_stream (ob, &state->streams[i]); +} + + +/* Write all the references in an lto_out_decl_state STATE using + output block OB and output stream OUT_STREAM. */ + +static void +lto_output_decl_state_refs (struct output_block *ob, + struct lto_output_stream *out_stream, + struct lto_out_decl_state *state) +{ + unsigned i; + int32_t ref; + tree decl; + + /* Write reference to FUNCTION_DECL. If there is not function, + write reference to void_type_node. */ + decl = (state->fn_decl) ? state->fn_decl : void_type_node; + lto_streamer_cache_lookup (ob->writer_cache, decl, &ref); + gcc_assert (ref >= 0); + lto_output_data_stream (out_stream, &ref, sizeof (int32_t)); + + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + write_global_references (ob, out_stream, &state->streams[i]); +} + + +/* Return the written size of STATE. */ + +static size_t +lto_out_decl_state_written_size (struct lto_out_decl_state *state) +{ + int i; + size_t size; + + size = sizeof (int32_t); /* fn_ref. */ + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + { + size += sizeof (int32_t); /* vector size. */ + size += (lto_tree_ref_encoder_size (&state->streams[i]) + * sizeof (int32_t)); + } + return size; +} + + +/* Helper function of write_symbols_of_kind. CACHE is the streamer + cache with all the pickled nodes. STREAM is the stream where to + write the table. V is a vector with the DECLs that should be on + the table. SEEN is a bitmap of symbols written so far. */ + +static void +write_symbol_vec (struct lto_streamer_cache_d *cache, + struct lto_output_stream *stream, + VEC(tree,heap) *v, bitmap seen) +{ + tree t; + int index; + + for (index = 0; VEC_iterate(tree, v, index, t); index++) + { + const char *name; + enum gcc_plugin_symbol_kind kind; + enum gcc_plugin_symbol_visibility visibility; + int slot_num; + uint64_t size; + const char *comdat; + + /* None of the following kinds of symbols are needed in the + symbol table. */ + if (!TREE_PUBLIC (t) + || is_builtin_fn (t) + || DECL_ABSTRACT (t) + || TREE_CODE (t) == RESULT_DECL) + continue; + + gcc_assert (TREE_CODE (t) == VAR_DECL + || TREE_CODE (t) == FUNCTION_DECL); + + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t)); + + /* FIXME lto: this is from assemble_name_raw in varasm.c. For some + architectures we might have to do the same name manipulations that + ASM_OUTPUT_LABELREF does. */ + if (name[0] == '*') + name = &name[1]; + + lto_streamer_cache_lookup (cache, t, &slot_num); + gcc_assert (slot_num >= 0); + + /* Avoid duplicate symbols. */ + if (bitmap_bit_p (seen, slot_num)) + continue; + else + bitmap_set_bit (seen, slot_num); + + if (DECL_EXTERNAL (t)) + { + if (DECL_WEAK (t)) + kind = GCCPK_WEAKUNDEF; + else + kind = GCCPK_UNDEF; + } + else + { + if (DECL_WEAK (t)) + kind = GCCPK_WEAKDEF; + else if (DECL_COMMON (t)) + kind = GCCPK_COMMON; + else + kind = GCCPK_DEF; + } + + switch (DECL_VISIBILITY(t)) + { + case VISIBILITY_DEFAULT: + visibility = GCCPV_DEFAULT; + break; + case VISIBILITY_PROTECTED: + visibility = GCCPV_PROTECTED; + break; + case VISIBILITY_HIDDEN: + visibility = GCCPV_HIDDEN; + break; + case VISIBILITY_INTERNAL: + visibility = GCCPV_INTERNAL; + break; + } + + if (kind == GCCPK_COMMON && DECL_SIZE (t)) + size = (((uint64_t) TREE_INT_CST_HIGH (DECL_SIZE (t))) << 32) + | TREE_INT_CST_LOW (DECL_SIZE (t)); + else + size = 0; + + if (DECL_ONE_ONLY (t)) + comdat = IDENTIFIER_POINTER (DECL_COMDAT_GROUP (t)); + else + comdat = ""; + + lto_output_data_stream (stream, name, strlen (name) + 1); + lto_output_data_stream (stream, comdat, strlen (comdat) + 1); + lto_output_data_stream (stream, &kind, 1); + lto_output_data_stream (stream, &visibility, 1); + lto_output_data_stream (stream, &size, 8); + lto_output_data_stream (stream, &slot_num, 4); + } +} + + +/* Write IL symbols of KIND. CACHE is the streamer cache with all the + pickled nodes. SEEN is a bitmap of symbols written so far. */ + +static void +write_symbols_of_kind (lto_decl_stream_e_t kind, + struct lto_streamer_cache_d *cache, bitmap seen) +{ + struct lto_out_decl_state *out_state; + struct lto_output_stream stream; + unsigned num_fns = + VEC_length (lto_out_decl_state_ptr, lto_function_decl_states); + unsigned idx; + + memset (&stream, 0, sizeof (stream)); + out_state = lto_get_out_decl_state (); + write_symbol_vec (cache, &stream, out_state->streams[kind].trees, seen); + + for (idx = 0; idx < num_fns; idx++) + { + out_state = + VEC_index (lto_out_decl_state_ptr, lto_function_decl_states, idx); + write_symbol_vec (cache, &stream, out_state->streams[kind].trees, seen); + } + + lto_write_stream (&stream); +} + + +/* Write an IL symbol table. CACHE is the streamer cache with all the + pickled nodes. */ + +static void +produce_symtab (struct lto_streamer_cache_d *cache) +{ + char *section_name = lto_get_section_name (LTO_section_symtab, NULL); + bitmap seen; + + lto_begin_section (section_name, false); + free (section_name); + + seen = lto_bitmap_alloc (); + write_symbols_of_kind (LTO_DECL_STREAM_FN_DECL, cache, seen); + write_symbols_of_kind (LTO_DECL_STREAM_VAR_DECL, cache, seen); + lto_bitmap_free (seen); + + lto_end_section (); +} + + +/* This pass is run after all of the functions are serialized and all + of the IPA passes have written their serialized forms. This pass + causes the vector of all of the global decls and types used from + this file to be written in to a section that can then be read in to + recover these on other side. */ + +static void +produce_asm_for_decls (cgraph_node_set set) +{ + struct lto_out_decl_state *out_state; + struct lto_out_decl_state *fn_out_state; + struct lto_decl_header header; + char *section_name; + struct output_block *ob; + struct lto_output_stream *header_stream, *decl_state_stream; + unsigned idx, num_fns; + size_t decl_state_size; + int32_t num_decl_states; + + ob = create_output_block (LTO_section_decls); + ob->global = true; + + /* Write out unreferenced globals, alias pairs and labels. We defer + doing this until now so that we can write out only what is + needed. */ + output_unreferenced_globals (set); + + memset (&header, 0, sizeof (struct lto_decl_header)); + + section_name = lto_get_section_name (LTO_section_decls, NULL); + lto_begin_section (section_name, !flag_wpa); + free (section_name); + + /* Make string 0 be a NULL string. */ + lto_output_1_stream (ob->string_stream, 0); + + /* Write the global symbols. */ + out_state = lto_get_out_decl_state (); + num_fns = VEC_length (lto_out_decl_state_ptr, lto_function_decl_states); + lto_output_decl_state_streams (ob, out_state); + for (idx = 0; idx < num_fns; idx++) + { + fn_out_state = + VEC_index (lto_out_decl_state_ptr, lto_function_decl_states, idx); + lto_output_decl_state_streams (ob, fn_out_state); + } + + header.lto_header.major_version = LTO_major_version; + header.lto_header.minor_version = LTO_minor_version; + header.lto_header.section_type = LTO_section_decls; + + /* Currently not used. This field would allow us to preallocate + the globals vector, so that it need not be resized as it is extended. */ + header.num_nodes = -1; + + /* Compute the total size of all decl out states. */ + decl_state_size = sizeof (int32_t); + decl_state_size += lto_out_decl_state_written_size (out_state); + for (idx = 0; idx < num_fns; idx++) + { + fn_out_state = + VEC_index (lto_out_decl_state_ptr, lto_function_decl_states, idx); + decl_state_size += lto_out_decl_state_written_size (fn_out_state); + } + header.decl_state_size = decl_state_size; + + header.main_size = ob->main_stream->total_size; + header.string_size = ob->string_stream->total_size; + + header_stream = XCNEW (struct lto_output_stream); + lto_output_data_stream (header_stream, &header, sizeof header); + lto_write_stream (header_stream); + free (header_stream); + + /* Write the main out-decl state, followed by out-decl states of + functions. */ + decl_state_stream = ((struct lto_output_stream *) + xcalloc (1, sizeof (struct lto_output_stream))); + num_decl_states = num_fns + 1; + lto_output_data_stream (decl_state_stream, &num_decl_states, + sizeof (num_decl_states)); + lto_output_decl_state_refs (ob, decl_state_stream, out_state); + for (idx = 0; idx < num_fns; idx++) + { + fn_out_state = + VEC_index (lto_out_decl_state_ptr, lto_function_decl_states, idx); + lto_output_decl_state_refs (ob, decl_state_stream, fn_out_state); + } + lto_write_stream (decl_state_stream); + free(decl_state_stream); + + lto_write_stream (ob->main_stream); + lto_write_stream (ob->string_stream); + + lto_end_section (); + + /* Write the symbol table. */ + produce_symtab (ob->writer_cache); + + /* Write command line opts. */ + lto_write_options (); + + /* Deallocate memory and clean up. */ + lto_cgraph_encoder_delete (ob->decl_state->cgraph_node_encoder); + VEC_free (lto_out_decl_state_ptr, heap, lto_function_decl_states); + lto_function_decl_states = NULL; + destroy_output_block (ob); +} + + +struct ipa_opt_pass_d pass_ipa_lto_finish_out = +{ + { + IPA_PASS, + "lto_decls_out", /* name */ + gate_lto_out, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_IPA_LTO_DECL_IO, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + 0 /* todo_flags_finish */ + }, + NULL, /* generate_summary */ + produce_asm_for_decls, /* write_summary */ + NULL, /* read_summary */ + NULL, /* function_read_summary */ + 0, /* TODOs */ + NULL, /* function_transform */ + NULL /* variable_transform */ +}; diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c new file mode 100644 index 00000000000..5b925db504e --- /dev/null +++ b/gcc/lto-streamer.c @@ -0,0 +1,863 @@ +/* Miscellaneous utilities for GIMPLE streaming. Things that are used + in both input and output are here. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Doug Kwan + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "flags.h" +#include "tree.h" +#include "gimple.h" +#include "tree-flow.h" +#include "diagnostic.h" +#include "bitmap.h" +#include "vec.h" +#include "lto-streamer.h" + +/* Statistics gathered during LTO, WPA and LTRANS. */ +struct lto_stats_d lto_stats; + +/* LTO uses bitmaps with different life-times. So use a seperate + obstack for all LTO bitmaps. */ +static bitmap_obstack lto_obstack; +static bool lto_obstack_initialized; + + +/* Return a string representing LTO tag TAG. */ + +const char * +lto_tag_name (enum LTO_tags tag) +{ + if (lto_tag_is_tree_code_p (tag)) + { + /* For tags representing tree nodes, return the name of the + associated tree code. */ + return tree_code_name[lto_tag_to_tree_code (tag)]; + } + + if (lto_tag_is_gimple_code_p (tag)) + { + /* For tags representing gimple statements, return the name of + the associated gimple code. */ + return gimple_code_name[lto_tag_to_gimple_code (tag)]; + } + + switch (tag) + { + case LTO_null: + return "LTO_null"; + case LTO_bb0: + return "LTO_bb0"; + case LTO_bb1: + return "LTO_bb1"; + case LTO_eh_region: + return "LTO_eh_region"; + case LTO_function: + return "LTO_function"; + case LTO_eh_table: + return "LTO_eh_table"; + case LTO_ert_cleanup: + return "LTO_ert_cleanup"; + case LTO_ert_try: + return "LTO_ert_try"; + case LTO_ert_allowed_exceptions: + return "LTO_ert_allowed_exceptions"; + case LTO_ert_must_not_throw: + return "LTO_ert_must_not_throw"; + case LTO_tree_pickle_reference: + return "LTO_tree_pickle_reference"; + case LTO_field_decl_ref: + return "LTO_field_decl_ref"; + case LTO_function_decl_ref: + return "LTO_function_decl_ref"; + case LTO_label_decl_ref: + return "LTO_label_decl_ref"; + case LTO_namespace_decl_ref: + return "LTO_namespace_decl_ref"; + case LTO_result_decl_ref: + return "LTO_result_decl_ref"; + case LTO_ssa_name_ref: + return "LTO_ssa_name_ref"; + case LTO_type_decl_ref: + return "LTO_type_decl_ref"; + case LTO_type_ref: + return "LTO_type_ref"; + case LTO_global_decl_ref: + return "LTO_global_decl_ref"; + default: + return "LTO_UNKNOWN"; + } +} + + +/* Allocate a bitmap from heap. Initializes the LTO obstack if necessary. */ + +bitmap +lto_bitmap_alloc (void) +{ + if (!lto_obstack_initialized) + { + bitmap_obstack_initialize (<o_obstack); + lto_obstack_initialized = true; + } + return BITMAP_ALLOC (<o_obstack); +} + +/* Free bitmap B. */ + +void +lto_bitmap_free (bitmap b) +{ + BITMAP_FREE (b); +} + + +/* Get a section name for a particular type or name. The NAME field + is only used if SECTION_TYPE is LTO_section_function_body or + LTO_static_initializer. For all others it is ignored. The callee + of this function is responcible to free the returned name. */ + +char * +lto_get_section_name (int section_type, const char *name) +{ + switch (section_type) + { + case LTO_section_function_body: + return concat (LTO_SECTION_NAME_PREFIX, name, NULL); + + case LTO_section_static_initializer: + return concat (LTO_SECTION_NAME_PREFIX, ".statics", NULL); + + case LTO_section_symtab: + return concat (LTO_SECTION_NAME_PREFIX, ".symtab", NULL); + + case LTO_section_decls: + return concat (LTO_SECTION_NAME_PREFIX, ".decls", NULL); + + case LTO_section_cgraph: + return concat (LTO_SECTION_NAME_PREFIX, ".cgraph", NULL); + + case LTO_section_jump_functions: + return concat (LTO_SECTION_NAME_PREFIX, ".jmpfuncs", NULL); + + case LTO_section_ipa_pure_const: + return concat (LTO_SECTION_NAME_PREFIX, ".pureconst", NULL); + + case LTO_section_ipa_reference: + return concat (LTO_SECTION_NAME_PREFIX, ".reference", NULL); + + case LTO_section_wpa_fixup: + return concat (LTO_SECTION_NAME_PREFIX, ".wpa_fixup", NULL); + + case LTO_section_opts: + return concat (LTO_SECTION_NAME_PREFIX, ".opts", NULL); + + default: + internal_error ("bytecode stream: unexpected LTO section %s", name); + } +} + + +/* Show various memory usage statistics related to LTO. */ + +void +print_lto_report (void) +{ + const char *s = (flag_lto) ? "LTO" : (flag_wpa) ? "WPA" : "LTRANS"; + unsigned i; + + fprintf (stderr, "%s statistics\n", s); + fprintf (stderr, "[%s] # of input files: " + HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, lto_stats.num_input_files); + + fprintf (stderr, "[%s] # of input cgraph nodes: " + HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, + lto_stats.num_input_cgraph_nodes); + + fprintf (stderr, "[%s] # of function bodies: " + HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, + lto_stats.num_function_bodies); + + fprintf (stderr, "[%s] ", s); + print_gimple_types_stats (); + + for (i = 0; i < NUM_TREE_CODES; i++) + if (lto_stats.num_trees[i]) + fprintf (stderr, "[%s] # of '%s' objects read: " + HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, + tree_code_name[i], lto_stats.num_trees[i]); + + if (flag_lto) + { + fprintf (stderr, "[%s] Compression: " + HOST_WIDE_INT_PRINT_UNSIGNED " output bytes, " + HOST_WIDE_INT_PRINT_UNSIGNED " compressed bytes", s, + lto_stats.num_output_il_bytes, + lto_stats.num_compressed_il_bytes); + if (lto_stats.num_output_il_bytes > 0) + { + const float dividend = (float) lto_stats.num_compressed_il_bytes; + const float divisor = (float) lto_stats.num_output_il_bytes; + fprintf (stderr, " (ratio: %f)", dividend / divisor); + } + fprintf (stderr, "\n"); + } + + if (flag_wpa) + { + fprintf (stderr, "[%s] # of output files: " + HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, + lto_stats.num_output_files); + + fprintf (stderr, "[%s] # of output cgraph nodes: " + HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, + lto_stats.num_output_cgraph_nodes); + + fprintf (stderr, "[%s] # callgraph partitions: " + HOST_WIDE_INT_PRINT_UNSIGNED "\n", s, + lto_stats.num_cgraph_partitions); + + fprintf (stderr, "[%s] Compression: " + HOST_WIDE_INT_PRINT_UNSIGNED " input bytes, " + HOST_WIDE_INT_PRINT_UNSIGNED " uncompressed bytes", s, + lto_stats.num_input_il_bytes, + lto_stats.num_uncompressed_il_bytes); + if (lto_stats.num_input_il_bytes > 0) + { + const float dividend = (float) lto_stats.num_uncompressed_il_bytes; + const float divisor = (float) lto_stats.num_input_il_bytes; + fprintf (stderr, " (ratio: %f)", dividend / divisor); + } + fprintf (stderr, "\n"); + } + + for (i = 0; i < LTO_N_SECTION_TYPES; i++) + fprintf (stderr, "[%s] Size of mmap'd section %s: " + HOST_WIDE_INT_PRINT_UNSIGNED " bytes\n", s, + lto_section_name[i], lto_stats.section_size[i]); +} + + +/* Create a new bitpack. */ + +struct bitpack_d * +bitpack_create (void) +{ + return XCNEW (struct bitpack_d); +} + + +/* Free the memory used by bitpack BP. */ + +void +bitpack_delete (struct bitpack_d *bp) +{ + VEC_free (bitpack_word_t, heap, bp->values); + free (bp); +} + + +/* Return an index to the word in bitpack BP that contains the + next NBITS. */ + +static inline unsigned +bp_get_next_word (struct bitpack_d *bp, unsigned nbits) +{ + unsigned last, ix; + + /* In principle, the next word to use is determined by the + number of bits already processed in BP. */ + ix = bp->num_bits / BITS_PER_BITPACK_WORD; + + /* All the encoded bit patterns in BP are contiguous, therefore if + the next NBITS would straddle over two different words, move the + index to the next word and update the number of encoded bits + by adding up the hole of unused bits created by this move. */ + bp->first_unused_bit %= BITS_PER_BITPACK_WORD; + last = bp->first_unused_bit + nbits - 1; + if (last >= BITS_PER_BITPACK_WORD) + { + ix++; + bp->num_bits += (BITS_PER_BITPACK_WORD - bp->first_unused_bit); + bp->first_unused_bit = 0; + } + + return ix; +} + + +/* Pack NBITS of value VAL into bitpack BP. */ + +void +bp_pack_value (struct bitpack_d *bp, bitpack_word_t val, unsigned nbits) +{ + unsigned ix; + bitpack_word_t word; + + /* We cannot encode more bits than BITS_PER_BITPACK_WORD. */ + gcc_assert (nbits > 0 && nbits <= BITS_PER_BITPACK_WORD); + + /* Compute which word will contain the next NBITS. */ + ix = bp_get_next_word (bp, nbits); + if (ix >= VEC_length (bitpack_word_t, bp->values)) + { + /* If there is no room left in the last word of the values + array, add a new word. Additionally, we should only + need to add a single word, since every pack operation cannot + use more bits than fit in a single word. */ + gcc_assert (ix < VEC_length (bitpack_word_t, bp->values) + 1); + VEC_safe_push (bitpack_word_t, heap, bp->values, 0); + } + + /* Grab the last word to pack VAL into. */ + word = VEC_index (bitpack_word_t, bp->values, ix); + + /* To fit VAL in WORD, we need to shift VAL to the left to + skip the bottom BP->FIRST_UNUSED_BIT bits. */ + gcc_assert (BITS_PER_BITPACK_WORD >= bp->first_unused_bit + nbits); + val <<= bp->first_unused_bit; + + /* Update WORD with VAL. */ + word |= val; + + /* Update BP. */ + VEC_replace (bitpack_word_t, bp->values, ix, word); + bp->num_bits += nbits; + bp->first_unused_bit += nbits; +} + + +/* Unpack the next NBITS from bitpack BP. */ + +bitpack_word_t +bp_unpack_value (struct bitpack_d *bp, unsigned nbits) +{ + bitpack_word_t val, word, mask; + unsigned ix; + + /* We cannot decode more bits than BITS_PER_BITPACK_WORD. */ + gcc_assert (nbits > 0 && nbits <= BITS_PER_BITPACK_WORD); + + /* Compute which word contains the next NBITS. */ + ix = bp_get_next_word (bp, nbits); + word = VEC_index (bitpack_word_t, bp->values, ix); + + /* Compute the mask to get NBITS from WORD. */ + mask = (nbits == BITS_PER_BITPACK_WORD) + ? (bitpack_word_t) -1 + : ((bitpack_word_t) 1 << nbits) - 1; + + /* Shift WORD to the right to skip over the bits already decoded + in word. */ + word >>= bp->first_unused_bit; + + /* Apply the mask to obtain the requested value. */ + val = word & mask; + + /* Update BP->NUM_BITS for the next unpack operation. */ + bp->num_bits += nbits; + bp->first_unused_bit += nbits; + + return val; +} + + +/* Check that all the TS_* structures handled by the lto_output_* and + lto_input_* routines are exactly ALL the structures defined in + treestruct.def. */ + +static void +check_handled_ts_structures (void) +{ + bool handled_p[LAST_TS_ENUM]; + unsigned i; + + memset (&handled_p, 0, sizeof (handled_p)); + + /* These are the TS_* structures that are either handled or + explicitly ignored by the streamer routines. */ + handled_p[TS_BASE] = true; + handled_p[TS_COMMON] = true; + handled_p[TS_INT_CST] = true; + handled_p[TS_REAL_CST] = true; + handled_p[TS_FIXED_CST] = true; + handled_p[TS_VECTOR] = true; + handled_p[TS_STRING] = true; + handled_p[TS_COMPLEX] = true; + handled_p[TS_IDENTIFIER] = true; + handled_p[TS_DECL_MINIMAL] = true; + handled_p[TS_DECL_COMMON] = true; + handled_p[TS_DECL_WRTL] = true; + handled_p[TS_DECL_NON_COMMON] = true; + handled_p[TS_DECL_WITH_VIS] = true; + handled_p[TS_FIELD_DECL] = true; + handled_p[TS_VAR_DECL] = true; + handled_p[TS_PARM_DECL] = true; + handled_p[TS_LABEL_DECL] = true; + handled_p[TS_RESULT_DECL] = true; + handled_p[TS_CONST_DECL] = true; + handled_p[TS_TYPE_DECL] = true; + handled_p[TS_FUNCTION_DECL] = true; + handled_p[TS_TYPE] = true; + handled_p[TS_LIST] = true; + handled_p[TS_VEC] = true; + handled_p[TS_EXP] = true; + handled_p[TS_SSA_NAME] = true; + handled_p[TS_BLOCK] = true; + handled_p[TS_BINFO] = true; + handled_p[TS_STATEMENT_LIST] = true; + handled_p[TS_CONSTRUCTOR] = true; + handled_p[TS_OMP_CLAUSE] = true; + handled_p[TS_OPTIMIZATION] = true; + handled_p[TS_TARGET_OPTION] = true; + + /* Anything not marked above will trigger the following assertion. + If this assertion triggers, it means that there is a new TS_* + structure that should be handled by the streamer. */ + for (i = 0; i < LAST_TS_ENUM; i++) + gcc_assert (handled_p[i]); +} + + +/* Helper for lto_streamer_cache_insert_1. Add T to CACHE->NODES at + slot IX. Add OFFSET to CACHE->OFFSETS at slot IX. */ + +static void +lto_streamer_cache_add_to_node_array (struct lto_streamer_cache_d *cache, + int ix, tree t, unsigned offset) +{ + gcc_assert (ix >= 0); + + /* Grow the array of nodes and offsets to accomodate T at IX. */ + if (ix >= (int) VEC_length (tree, cache->nodes)) + { + size_t sz = ix + (20 + ix) / 4; + VEC_safe_grow_cleared (tree, gc, cache->nodes, sz); + VEC_safe_grow_cleared (unsigned, heap, cache->offsets, sz); + } + + VEC_replace (tree, cache->nodes, ix, t); + VEC_replace (unsigned, cache->offsets, ix, offset); +} + + +/* Helper for lto_streamer_cache_insert and lto_streamer_cache_insert_at. + CACHE, T, IX_P and OFFSET_P are as in lto_streamer_cache_insert. + + If INSERT_AT_NEXT_SLOT_P is true, T is inserted at the next available + slot in the cache. Otherwise, T is inserted at the position indicated + in *IX_P. + + If T already existed in CACHE, return true. Otherwise, + return false. */ + +static bool +lto_streamer_cache_insert_1 (struct lto_streamer_cache_d *cache, + tree t, int *ix_p, unsigned *offset_p, + bool insert_at_next_slot_p) +{ + void **slot; + struct tree_int_map d_entry, *entry; + int ix; + unsigned offset; + bool existed_p; + + gcc_assert (t); + + d_entry.base.from = t; + slot = htab_find_slot (cache->node_map, &d_entry, INSERT); + if (*slot == NULL) + { + /* Determine the next slot to use in the cache. */ + if (insert_at_next_slot_p) + ix = cache->next_slot++; + else + ix = *ix_p; + + entry = XCNEW (struct tree_int_map); + entry->base.from = t; + entry->to = (unsigned) ix; + *slot = entry; + + /* If no offset was given, store the invalid offset -1. */ + offset = (offset_p) ? *offset_p : (unsigned) -1; + + lto_streamer_cache_add_to_node_array (cache, ix, t, offset); + + /* Indicate that the item was not present in the cache. */ + existed_p = false; + } + else + { + entry = (struct tree_int_map *) *slot; + ix = (int) entry->to; + offset = VEC_index (unsigned, cache->offsets, ix); + + if (!insert_at_next_slot_p && ix != *ix_p) + { + /* If the caller wants to insert T at a specific slot + location, and ENTRY->TO does not match *IX_P, add T to + the requested location slot. This situation arises when + streaming builtin functions. + + For instance, on the writer side we could have two + FUNCTION_DECLS T1 and T2 that are represented by the same + builtin function. The reader will only instantiate the + canonical builtin, but since T1 and T2 had been + originally stored in different cache slots (S1 and S2), + the reader must be able to find the canonical builtin + function at slots S1 and S2. */ + gcc_assert (lto_stream_as_builtin_p (t)); + ix = *ix_p; + + /* Since we are storing a builtin, the offset into the + stream is not necessary as we will not need to read + forward in the stream. */ + lto_streamer_cache_add_to_node_array (cache, ix, t, -1); + } + + /* Indicate that T was already in the cache. */ + existed_p = true; + } + + if (ix_p) + *ix_p = ix; + + if (offset_p) + *offset_p = offset; + + return existed_p; +} + + +/* Insert tree node T in CACHE. If T already existed in the cache + return true. Otherwise, return false. + + If IX_P is non-null, update it with the index into the cache where + T has been stored. + + *OFFSET_P represents the offset in the stream where T is physically + written out. The first time T is added to the cache, *OFFSET_P is + recorded in the cache together with T. But if T already existed + in the cache, *OFFSET_P is updated with the value that was recorded + the first time T was added to the cache. + + If OFFSET_P is NULL, it is ignored. */ + +bool +lto_streamer_cache_insert (struct lto_streamer_cache_d *cache, tree t, + int *ix_p, unsigned *offset_p) +{ + return lto_streamer_cache_insert_1 (cache, t, ix_p, offset_p, true); +} + + +/* Insert tree node T in CACHE at slot IX. If T already + existed in the cache return true. Otherwise, return false. */ + +bool +lto_streamer_cache_insert_at (struct lto_streamer_cache_d *cache, + tree t, int ix) +{ + return lto_streamer_cache_insert_1 (cache, t, &ix, NULL, false); +} + + +/* Return true if tree node T exists in CACHE. If IX_P is + not NULL, write to *IX_P the index into the cache where T is stored + (-1 if T is not found). */ + +bool +lto_streamer_cache_lookup (struct lto_streamer_cache_d *cache, tree t, + int *ix_p) +{ + void **slot; + struct tree_int_map d_slot; + bool retval; + int ix; + + gcc_assert (t); + + d_slot.base.from = t; + slot = htab_find_slot (cache->node_map, &d_slot, NO_INSERT); + if (slot == NULL) + { + retval = false; + ix = -1; + } + else + { + retval = true; + ix = (int) ((struct tree_int_map *) *slot)->to; + } + + if (ix_p) + *ix_p = ix; + + return retval; +} + + +/* Return the tree node at slot IX in CACHE. */ + +tree +lto_streamer_cache_get (struct lto_streamer_cache_d *cache, int ix) +{ + gcc_assert (cache); + + /* If the reader is requesting an index beyond the length of the + cache, it will need to read ahead. Return NULL_TREE to indicate + that. */ + if ((unsigned) ix >= VEC_length (tree, cache->nodes)) + return NULL_TREE; + + return VEC_index (tree, cache->nodes, (unsigned) ix); +} + + +/* Record NODE in COMMON_NODES if it is not NULL and is not already in + SEEN_NODES. */ + +static void +lto_record_common_node (tree *nodep, VEC(tree, heap) **common_nodes, + struct pointer_set_t *seen_nodes) +{ + tree node = *nodep; + + if (node == NULL_TREE) + return; + + if (TYPE_P (node)) + *nodep = node = gimple_register_type (node); + + /* Return if node is already seen. */ + if (pointer_set_insert (seen_nodes, node)) + return; + + VEC_safe_push (tree, heap, *common_nodes, node); + + if (tree_node_can_be_shared (node)) + { + if (POINTER_TYPE_P (node) + || TREE_CODE (node) == COMPLEX_TYPE + || TREE_CODE (node) == ARRAY_TYPE) + lto_record_common_node (&TREE_TYPE (node), common_nodes, seen_nodes); + } +} + + +/* Generate a vector of common nodes and make sure they are merged + properly according to the the gimple type table. */ + +static VEC(tree,heap) * +lto_get_common_nodes (void) +{ + unsigned i; + VEC(tree,heap) *common_nodes = NULL; + struct pointer_set_t *seen_nodes; + + /* The MAIN_IDENTIFIER_NODE is normally set up by the front-end, but the + LTO back-end must agree. Currently, the only languages that set this + use the name "main". */ + if (main_identifier_node) + { + const char *main_name = IDENTIFIER_POINTER (main_identifier_node); + gcc_assert (strcmp (main_name, "main") == 0); + } + else + main_identifier_node = get_identifier ("main"); + + gcc_assert (ptrdiff_type_node == integer_type_node); + + /* FIXME lto. In the C++ front-end, fileptr_type_node is defined as a + variant copy of of ptr_type_node, rather than ptr_node itself. The + distinction should only be relevant to the front-end, so we always + use the C definition here in lto1. + + These should be assured in pass_ipa_free_lang_data. */ + gcc_assert (fileptr_type_node == ptr_type_node); + gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node); + + seen_nodes = pointer_set_create (); + + /* Skip itk_char. char_type_node is shared with the appropriately + signed variant. */ + for (i = itk_signed_char; i < itk_none; i++) + lto_record_common_node (&integer_types[i], &common_nodes, seen_nodes); + + for (i = 0; i < TYPE_KIND_LAST; i++) + lto_record_common_node (&sizetype_tab[i], &common_nodes, seen_nodes); + + for (i = 0; i < TI_MAX; i++) + lto_record_common_node (&global_trees[i], &common_nodes, seen_nodes); + + pointer_set_destroy (seen_nodes); + + return common_nodes; +} + + +/* Assign an index to tree node T and enter it in the streamer cache + CACHE. */ + +static void +preload_common_node (struct lto_streamer_cache_d *cache, tree t) +{ + gcc_assert (t); + + lto_streamer_cache_insert (cache, t, NULL, NULL); + + /* The FIELD_DECLs of structures should be shared, so that every + COMPONENT_REF uses the same tree node when referencing a field. + Pointer equality between FIELD_DECLs is used by the alias + machinery to compute overlapping memory references (See + nonoverlapping_component_refs_p). */ + if (TREE_CODE (t) == RECORD_TYPE) + { + tree f; + + for (f = TYPE_FIELDS (t); f; f = TREE_CHAIN (f)) + preload_common_node (cache, f); + } +} + + +/* Create a cache of pickled nodes. */ + +struct lto_streamer_cache_d * +lto_streamer_cache_create (void) +{ + struct lto_streamer_cache_d *cache; + VEC(tree, heap) *common_nodes; + unsigned i; + tree node; + + cache = XCNEW (struct lto_streamer_cache_d); + + cache->node_map = htab_create (101, tree_int_map_hash, tree_int_map_eq, NULL); + + /* Load all the well-known tree nodes that are always created by + the compiler on startup. This prevents writing them out + unnecessarily. */ + common_nodes = lto_get_common_nodes (); + + for (i = 0; VEC_iterate (tree, common_nodes, i, node); i++) + preload_common_node (cache, node); + + VEC_free(tree, heap, common_nodes); + + return cache; +} + + +/* Delete the streamer cache C. */ + +void +lto_streamer_cache_delete (struct lto_streamer_cache_d *c) +{ + if (c == NULL) + return; + + htab_delete (c->node_map); + VEC_free (tree, gc, c->nodes); + VEC_free (unsigned, heap, c->offsets); + free (c); +} + + +/* Initialization common to the LTO reader and writer. */ + +void +lto_streamer_init (void) +{ + /* Check that all the TS_* handled by the reader and writer routines + match exactly the structures defined in treestruct.def. When a + new TS_* astructure is added, the streamer should be updated to + handle it. */ + check_handled_ts_structures (); +} + + +/* Gate function for all LTO streaming passes. */ + +bool +gate_lto_out (void) +{ + return ((flag_generate_lto || in_lto_p) + /* Don't bother doing anything if the program has errors. */ + && !(errorcount || sorrycount)); +} + + +#ifdef LTO_STREAMER_DEBUG +/* Add a mapping between T and ORIG_T, which is the numeric value of + the original address of T as it was seen by the LTO writer. This + mapping is useful when debugging streaming problems. A debugging + session can be started on both reader and writer using ORIG_T + as a breakpoint value in both sessions. + + Note that this mapping is transient and only valid while T is + being reconstructed. Once T is fully built, the mapping is + removed. */ + +void +lto_orig_address_map (tree t, intptr_t orig_t) +{ + /* FIXME lto. Using the annotation field is quite hacky as it relies + on the GC not running while T is being rematerialized. It would + be cleaner to use a hash table here. */ + t->base.ann = (union tree_ann_d *) orig_t; +} + + +/* Get the original address of T as it was seen by the writer. This + is only valid while T is being reconstructed. */ + +intptr_t +lto_orig_address_get (tree t) +{ + return (intptr_t) t->base.ann; +} + + +/* Clear the mapping of T to its original address. */ + +void +lto_orig_address_remove (tree t) +{ + t->base.ann = NULL; +} +#endif + + +/* Check that the version MAJOR.MINOR is the correct version number. */ + +void +lto_check_version (int major, int minor) +{ + if (major != LTO_major_version || minor != LTO_minor_version) + fatal_error ("bytecode stream generated with LTO version %d.%d instead " + "of the expected %d.%d", + major, minor, + LTO_major_version, LTO_minor_version); +} diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h new file mode 100644 index 00000000000..c3880b61efa --- /dev/null +++ b/gcc/lto-streamer.h @@ -0,0 +1,1046 @@ +/* Data structures and declarations used for reading and writing + GIMPLE to a file stream. + + Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Doug Kwan + +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 3, 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 COPYING3. If not see +. */ + +#ifndef GCC_LTO_STREAMER_H +#define GCC_LTO_STREAMER_H + +#include "plugin-api.h" +#include "tree.h" +#include "gimple.h" +#include "target.h" +#include "cgraph.h" +#include "vec.h" +#include "vecprim.h" + +/* Define when debugging the LTO streamer. This causes the writer + to output the numeric value for the memory address of the tree node + being emitted. When debugging a problem in the reader, check the + original address that the writer was emitting using lto_orig_address_get. + With this value, set a breakpoint in the writer (e.g., lto_output_tree) + to trace how the faulty node is being emitted. */ +/* #define LTO_STREAMER_DEBUG 1 */ + +/* The encoding for a function consists of the following sections: + + 1) The header. + 2) FIELD_DECLS. + 3) FUNCTION_DECLS. + 4) global VAR_DECLS. + 5) type_decls + 6) types. + 7) Names for the labels that have names + 8) The SSA names. + 9) The control flow graph. + 10-11)Gimple for local decls. + 12) Gimple for the function. + 13) Strings. + + 1) THE HEADER. + 2-6) THE GLOBAL DECLS AND TYPES. + + The global decls and types are encoded in the same way. For each + entry, there is word with the offset within the section to the + entry. + + 7) THE LABEL NAMES. + + Since most labels do not have names, this section my be of zero + length. It consists of an array of string table references, one + per label. In the lto code, the labels are given either + positive or negative indexes. the positive ones have names and + the negative ones do not. The positive index can be used to + find the name in this array. + + 9) THE CFG. + + 10) Index into the local decls. Since local decls can have local + decls inside them, they must be read in randomly in order to + properly restore them. + + 11-12) GIMPLE FOR THE LOCAL DECLS AND THE FUNCTION BODY. + + The gimple consists of a set of records. + + THE FUNCTION + + At the top level of (8) is the function. It consists of five + pieces: + + LTO_function - The tag. + eh tree - This is all of the exception handling regions + put out in a post order traversial of the + tree. Siblings are output as lists terminated + by a 0. The set of fields matches the fields + defined in except.c. + + last_basic_block - in uleb128 form. + + basic blocks - This is the set of basic blocks. + + zero - The termination of the basic blocks. + + BASIC BLOCKS + + There are two forms of basic blocks depending on if they are + empty or not. + + The basic block consists of: + + LTO_bb1 or LTO_bb0 - The tag. + + bb->index - the index in uleb128 form. + + #succs - The number of successors un uleb128 form. + + the successors - For each edge, a pair. The first of the + pair is the index of the successor in + uleb128 form and the second are the flags in + uleb128 form. + + the statements - A gimple tree, as described above. + These are only present for LTO_BB1. + Following each statement is an optional + exception handling record LTO_eh_region + which contains the region number (for + regions >= 0). + + zero - This is only present for LTO_BB1 and is used + to terminate the statements and exception + regions within this block. + + 12) STRINGS + + String are represented in the table as pairs, a length in ULEB128 + form followed by the data for the string. */ + +/* The string that is the prefix on the section names we make for lto. + For decls the DECL_ASSEMBLER_NAME is appended to make the section + name for the functions and static_initializers. For other types of + sections a '.' and the section type are appended. */ +#define LTO_SECTION_NAME_PREFIX ".gnu.lto_" + +#define LTO_major_version 1 +#define LTO_minor_version 0 + +typedef unsigned char lto_decl_flags_t; + + +/* Data structures used to pack values and bitflags into a vector of + words. Used to stream values of a fixed number of bits in a space + efficient way. */ +static unsigned const BITS_PER_BITPACK_WORD = HOST_BITS_PER_WIDE_INT; + +typedef unsigned HOST_WIDE_INT bitpack_word_t; +DEF_VEC_I(bitpack_word_t); +DEF_VEC_ALLOC_I(bitpack_word_t, heap); + +struct bitpack_d +{ + /* Total number of bits packed/unpacked so far. */ + size_t num_bits; + + /* Values are stored contiguously, so there may be internal + fragmentation (words with unused bits). Therefore, we need to + keep track of the first available bit in the last word of the + bitpack. */ + size_t first_unused_bit; + + /* Vector of words holding the packed values. */ + VEC(bitpack_word_t, heap) *values; +}; + +/* Tags representing the various IL objects written to the bytecode file + (GIMPLE statements, basic blocks, EH regions, tree nodes, etc). + + NOTE, when adding new LTO tags, also update lto_tag_name. */ +enum LTO_tags +{ + LTO_null = 0, + + /* Reserve enough entries to fit all the tree and gimple codes handled + by the streamer. This guarantees that: + + 1- Given a tree code C: + enum LTO_tags tag == C + 1 + + 2- Given a gimple code C: + enum LTO_tags tag == C + NUM_TREE_CODES + 1 + + Conversely, to map between LTO tags and tree/gimple codes, the + reverse operation must be applied. */ + LTO_bb0 = 1 + NUM_TREE_CODES + LAST_AND_UNUSED_GIMPLE_CODE, + LTO_bb1, + + /* EH region holding the previous statement. */ + LTO_eh_region, + + /* An MD or NORMAL builtin. Only the code and class are streamed out. */ + LTO_builtin_decl, + + /* Function body. */ + LTO_function, + + /* EH table. */ + LTO_eh_table, + + /* EH region types. These mirror enum eh_region_type. */ + LTO_ert_cleanup, + LTO_ert_try, + LTO_ert_allowed_exceptions, + LTO_ert_must_not_throw, + + /* EH landing pad. */ + LTO_eh_landing_pad, + + /* EH try/catch node. */ + LTO_eh_catch, + + /* Special for global streamer. Reference to previously-streamed node. */ + LTO_tree_pickle_reference, + + /* References to indexable tree nodes. These objects are stored in + tables that are written separately from the function bodies that + reference them. This way they can be instantiated even when the + referencing functions aren't (e.g., during WPA) and it also allows + functions to be copied from one file to another without having + to unpickle the body first (the references are location + independent). + + NOTE, do not regroup these values as the grouping is exposed + in the range checks done in lto_input_tree. */ + LTO_field_decl_ref, /* Do not change. */ + LTO_function_decl_ref, + LTO_label_decl_ref, + LTO_namespace_decl_ref, + LTO_result_decl_ref, + LTO_ssa_name_ref, + LTO_type_decl_ref, + LTO_type_ref, + LTO_const_decl_ref, + LTO_imported_decl_ref, + LTO_global_decl_ref, /* Do not change. */ + + /* This tag must always be last. */ + LTO_NUM_TAGS +}; + + +/* Set of section types that are in an LTO file. This list will grow + as the number of IPA passes grows since each IPA pass will need its + own section type to store its summary information. + + When adding a new section type, you must also extend the + LTO_SECTION_NAME array in lto-section-in.c. */ +enum lto_section_type +{ + LTO_section_decls = 0, + LTO_section_function_body, + LTO_section_static_initializer, + LTO_section_cgraph, + LTO_section_jump_functions, + LTO_section_ipa_pure_const, + LTO_section_ipa_reference, + LTO_section_symtab, + LTO_section_wpa_fixup, + LTO_section_opts, + LTO_N_SECTION_TYPES /* Must be last. */ +}; + +/* Indices to the various function, type and symbol streams. */ +typedef enum +{ + LTO_DECL_STREAM_TYPE = 0, /* Must be first. */ + LTO_DECL_STREAM_FIELD_DECL, + LTO_DECL_STREAM_FN_DECL, + LTO_DECL_STREAM_VAR_DECL, + LTO_DECL_STREAM_TYPE_DECL, + LTO_DECL_STREAM_NAMESPACE_DECL, + LTO_DECL_STREAM_LABEL_DECL, + LTO_N_DECL_STREAMS +} lto_decl_stream_e_t; + +typedef enum ld_plugin_symbol_resolution ld_plugin_symbol_resolution_t; +DEF_VEC_I(ld_plugin_symbol_resolution_t); +DEF_VEC_ALLOC_I(ld_plugin_symbol_resolution_t, heap); + + +/* Macro to define convenience functions for type and decl streams + in lto_file_decl_data. */ +#define DEFINE_DECL_STREAM_FUNCS(UPPER_NAME, name) \ +static inline tree \ +lto_file_decl_data_get_ ## name (struct lto_file_decl_data *data, \ + unsigned int idx) \ +{ \ + struct lto_in_decl_state *state = data->current_decl_state; \ + gcc_assert (idx < state->streams[LTO_DECL_STREAM_## UPPER_NAME].size); \ + return state->streams[LTO_DECL_STREAM_## UPPER_NAME].trees[idx]; \ +} \ +\ +static inline unsigned int \ +lto_file_decl_data_num_ ## name ## s (struct lto_file_decl_data *data) \ +{ \ + struct lto_in_decl_state *state = data->current_decl_state; \ + return state->streams[LTO_DECL_STREAM_## UPPER_NAME].size; \ +} + + +/* Return a char pointer to the start of a data stream for an lto pass + or function. The first parameter is the file data that contains + the information. The second parameter is the type of information + to be obtained. The third parameter is the name of the function + and is only used when finding a function body; otherwise it is + NULL. The fourth parameter is the length of the data returned. */ +typedef const char* (lto_get_section_data_f) (struct lto_file_decl_data *, + enum lto_section_type, + const char *, + size_t *); + +/* Return the data found from the above call. The first three + parameters are the same as above. The fourth parameter is the data + itself and the fifth is the lenght of the data. */ +typedef void (lto_free_section_data_f) (struct lto_file_decl_data *, + enum lto_section_type, + const char *, + const char *, + size_t); + +/* Cache of pickled nodes. Used to avoid writing the same node more + than once. The first time a tree node is streamed out, it is + entered in this cache. Subsequent references to the same node are + resolved by looking it up in this cache. + + This is used in two ways: + + - On the writing side, the first time T is added to STREAMER_CACHE, + a new reference index is created for T and T is emitted on the + stream. If T needs to be emitted again to the stream, instead of + pickling it again, the reference index is emitted. + + - On the reading side, the first time T is read from the stream, it + is reconstructed in memory and a new reference index created for + T. The reconstructed T is inserted in some array so that when + the reference index for T is found in the input stream, it can be + used to look up into the array to get the reconstructed T. */ +struct lto_streamer_cache_d +{ + /* The mapping between tree nodes and slots into the nodes array. */ + htab_t node_map; + + /* Next available slot in the nodes and offsets arrays. */ + unsigned next_slot; + + /* The nodes pickled so far. */ + VEC(tree,gc) *nodes; + + /* Offset into the stream where the nodes have been written. */ + VEC(unsigned,heap) *offsets; +}; + + +/* Structure used as buffer for reading an LTO file. */ +struct lto_input_block +{ + const char *data; + unsigned int p; + unsigned int len; +}; + +#define LTO_INIT_INPUT_BLOCK(BASE,D,P,L) \ + do { \ + BASE.data = D; \ + BASE.p = P; \ + BASE.len = L; \ + } while (0) + +#define LTO_INIT_INPUT_BLOCK_PTR(BASE,D,P,L) \ + do { \ + BASE->data = D; \ + BASE->p = P; \ + BASE->len = L; \ + } while (0) + + +/* The is the first part of the record for a function or constructor + in the .o file. */ +struct lto_header +{ + int16_t major_version; + int16_t minor_version; + enum lto_section_type section_type; +}; + +/* The header for a function body. */ +struct lto_function_header +{ + /* The header for all types of sections. */ + struct lto_header lto_header; + + /* Number of labels with names. */ + int32_t num_named_labels; + + /* Number of labels without names. */ + int32_t num_unnamed_labels; + + /* Size compressed or 0 if not compressed. */ + int32_t compressed_size; + + /* Size of names for named labels. */ + int32_t named_label_size; + + /* Size of the cfg. */ + int32_t cfg_size; + + /* Size of main gimple body of function. */ + int32_t main_size; + + /* Size of the string table. */ + int32_t string_size; +}; + + +/* Structure describing a symbol section. */ +struct lto_decl_header +{ + /* The header for all types of sections. */ + struct lto_header lto_header; + + /* Size of region for decl state. */ + int32_t decl_state_size; + + /* Number of nodes in globals stream. */ + int32_t num_nodes; + + /* Size of region for expressions, decls, types, etc. */ + int32_t main_size; + + /* Size of the string table. */ + int32_t string_size; +}; + + +/* Statistics gathered during LTO, WPA and LTRANS. */ +struct lto_stats_d +{ + unsigned HOST_WIDE_INT num_input_cgraph_nodes; + unsigned HOST_WIDE_INT num_output_cgraph_nodes; + unsigned HOST_WIDE_INT num_input_files; + unsigned HOST_WIDE_INT num_output_files; + unsigned HOST_WIDE_INT num_cgraph_partitions; + unsigned HOST_WIDE_INT section_size[LTO_N_SECTION_TYPES]; + unsigned HOST_WIDE_INT num_function_bodies; + unsigned HOST_WIDE_INT num_trees[NUM_TREE_CODES]; + unsigned HOST_WIDE_INT num_output_il_bytes; + unsigned HOST_WIDE_INT num_compressed_il_bytes; + unsigned HOST_WIDE_INT num_input_il_bytes; + unsigned HOST_WIDE_INT num_uncompressed_il_bytes; +}; + +/* Encoder data structure used to stream callgraph nodes. */ +struct lto_cgraph_encoder_d +{ + /* Map nodes to reference number. */ + struct pointer_map_t *map; + + /* Map reference number to node. */ + VEC(cgraph_node_ptr,heap) *nodes; +}; + +typedef struct lto_cgraph_encoder_d *lto_cgraph_encoder_t; + +/* Mapping from indices to trees. */ +struct lto_tree_ref_table +{ + /* Array of referenced trees . */ + tree *trees; + + /* Size of array. */ + unsigned int size; +}; + + +/* Mapping between trees and slots in an array. */ +struct lto_decl_slot +{ + tree t; + int slot_num; +}; + + +/* The lto_tree_ref_encoder struct is used to encode trees into indices. */ + +struct lto_tree_ref_encoder +{ + htab_t tree_hash_table; /* Maps pointers to indices. */ + unsigned int next_index; /* Next available index. */ + VEC(tree,heap) *trees; /* Maps indices to pointers. */ +}; + + +/* Structure to hold states of input scope. */ +struct lto_in_decl_state +{ + /* Array of lto_in_decl_buffers to store type and decls streams. */ + struct lto_tree_ref_table streams[LTO_N_DECL_STREAMS]; + + /* If this in-decl state is associated with a function. FN_DECL + point to the FUNCTION_DECL. */ + tree fn_decl; +}; + +typedef struct lto_in_decl_state *lto_in_decl_state_ptr; + + +/* The structure that holds all of the vectors of global types, + decls and cgraph nodes used in the serialization of this file. */ +struct lto_out_decl_state +{ + /* The buffers contain the sets of decls of various kinds and types we have + seen so far and the indexes assigned to them. */ + struct lto_tree_ref_encoder streams[LTO_N_DECL_STREAMS]; + + /* Encoder for cgraph nodes. */ + lto_cgraph_encoder_t cgraph_node_encoder; + + /* If this out-decl state belongs to a function, fn_decl points to that + function. Otherwise, it is NULL. */ + tree fn_decl; +}; + +typedef struct lto_out_decl_state *lto_out_decl_state_ptr; + +DEF_VEC_P(lto_out_decl_state_ptr); +DEF_VEC_ALLOC_P(lto_out_decl_state_ptr, heap); + +/* One of these is allocated for each object file that being compiled + by lto. This structure contains the tables that are needed by the + serialized functions and ipa passes to connect themselves to the + global types and decls as they are reconstituted. */ +struct lto_file_decl_data +{ + /* Decl state currently used. */ + struct lto_in_decl_state *current_decl_state; + + /* Decl state corresponding to regions outside of any functions + in the compilation unit. */ + struct lto_in_decl_state *global_decl_state; + + /* Table of cgraph nodes present in this file. */ + lto_cgraph_encoder_t cgraph_node_encoder; + + /* Hash table maps lto-related section names to location in file. */ + htab_t function_decl_states; + + /* The .o file that these offsets relate to. */ + const char *file_name; + + /* Nonzero if this file should be recompiled with LTRANS. */ + unsigned needs_ltrans_p : 1; + + /* Hash table maps lto-related section names to location in file. */ + htab_t section_hash_table; + + /* Hash new name of renamed global declaration to its original name. */ + htab_t renaming_hash_table; +}; + +struct lto_char_ptr_base +{ + char *ptr; +}; + +/* An incore byte stream to buffer the various parts of the function. + The entire structure should be zeroed when created. The record + consists of a set of blocks. The first sizeof (ptr) bytes are used + as a chain, and the rest store the bytes to be written. */ +struct lto_output_stream +{ + /* The pointer to the first block in the stream. */ + struct lto_char_ptr_base * first_block; + + /* The pointer to the last and current block in the stream. */ + struct lto_char_ptr_base * current_block; + + /* The pointer to where the next char should be written. */ + char * current_pointer; + + /* The number of characters left in the current block. */ + unsigned int left_in_block; + + /* The block size of the last block allocated. */ + unsigned int block_size; + + /* The total number of characters written. */ + unsigned int total_size; +}; + +/* The is the first part of the record in an LTO file for many of the + IPA passes. */ +struct lto_simple_header +{ + /* The header for all types of sections. */ + struct lto_header lto_header; + + /* Size of main gimple body of function. */ + int32_t main_size; + + /* Size of main stream when compressed. */ + int32_t compressed_size; +}; + +/* A simple output block. This can be used for simple IPA passes that + do not need more than one stream. */ +struct lto_simple_output_block +{ + enum lto_section_type section_type; + struct lto_out_decl_state *decl_state; + + /* The stream that the main tree codes are written to. */ + struct lto_output_stream *main_stream; +}; + +/* Data structure holding all the data and descriptors used when writing + an LTO file. */ +struct output_block +{ + enum lto_section_type section_type; + struct lto_out_decl_state *decl_state; + + /* The stream that the main tree codes are written to. */ + struct lto_output_stream *main_stream; + + /* The stream that contains the string table. */ + struct lto_output_stream *string_stream; + + /* The stream that contains the cfg. */ + struct lto_output_stream *cfg_stream; + + /* The hash table that contains the set of strings we have seen so + far and the indexes assigned to them. */ + htab_t string_hash_table; + + /* The current cgraph_node that we are currently serializing. Null + if we are serializing something else. */ + struct cgraph_node *cgraph_node; + + /* These are the last file and line that were seen in the stream. + If the current node differs from these, it needs to insert + something into the stream and fix these up. */ + const char *current_file; + int current_line; + int current_col; + + /* True if writing globals and types. */ + bool global; + + /* Cache of nodes written in this section. */ + struct lto_streamer_cache_d *writer_cache; +}; + + +/* Data and descriptors used when reading from an LTO file. */ +struct data_in +{ + /* The global decls and types. */ + struct lto_file_decl_data *file_data; + + /* All of the labels. */ + tree *labels; + + /* The string table. */ + const char *strings; + + /* The length of the string table. */ + unsigned int strings_len; + + /* Number of named labels. Used to find the index of unnamed labels + since they share space with the named labels. */ + unsigned int num_named_labels; + + /* Number of unnamed labels. */ + unsigned int num_unnamed_labels; + + const char *current_file; + int current_line; + int current_col; + + /* Maps each reference number to the resolution done by the linker. */ + VEC(ld_plugin_symbol_resolution_t,heap) *globals_resolution; + + /* Cache of pickled nodes. */ + struct lto_streamer_cache_d *reader_cache; +}; + + +/* In lto-section-in.c */ +extern struct lto_input_block * lto_create_simple_input_block ( + struct lto_file_decl_data *, + enum lto_section_type, const char **, size_t *); +extern void +lto_destroy_simple_input_block (struct lto_file_decl_data *, + enum lto_section_type, + struct lto_input_block *, const char *, size_t); +extern void lto_set_in_hooks (struct lto_file_decl_data **, + lto_get_section_data_f *, + lto_free_section_data_f *); +extern struct lto_file_decl_data **lto_get_file_decl_data (void); +extern const char *lto_get_section_data (struct lto_file_decl_data *, + enum lto_section_type, + const char *, size_t *); +extern void lto_free_section_data (struct lto_file_decl_data *, + enum lto_section_type, + const char *, const char *, size_t); +extern unsigned char lto_input_1_unsigned (struct lto_input_block *); +extern unsigned HOST_WIDE_INT lto_input_uleb128 (struct lto_input_block *); +extern unsigned HOST_WIDEST_INT lto_input_widest_uint_uleb128 ( + struct lto_input_block *); +extern HOST_WIDE_INT lto_input_sleb128 (struct lto_input_block *); +extern htab_t lto_create_renaming_table (void); +extern void lto_record_renamed_decl (struct lto_file_decl_data *, + const char *, const char *); +extern const char *lto_get_decl_name_mapping (struct lto_file_decl_data *, + const char *); +extern struct lto_in_decl_state *lto_new_in_decl_state (void); +extern void lto_delete_in_decl_state (struct lto_in_decl_state *); +extern hashval_t lto_hash_in_decl_state (const void *); +extern int lto_eq_in_decl_state (const void *, const void *); +extern struct lto_in_decl_state *lto_get_function_in_decl_state ( + struct lto_file_decl_data *, tree); + +/* In lto-section-out.c */ +extern hashval_t lto_hash_decl_slot_node (const void *); +extern int lto_eq_decl_slot_node (const void *, const void *); +extern hashval_t lto_hash_type_slot_node (const void *); +extern int lto_eq_type_slot_node (const void *, const void *); +extern void lto_begin_section (const char *, bool); +extern void lto_end_section (void); +extern void lto_write_stream (struct lto_output_stream *); +extern void lto_output_1_stream (struct lto_output_stream *, char); +extern void lto_output_data_stream (struct lto_output_stream *, const void *, + size_t); +extern void lto_output_uleb128_stream (struct lto_output_stream *, + unsigned HOST_WIDE_INT); +extern void lto_output_widest_uint_uleb128_stream (struct lto_output_stream *, + unsigned HOST_WIDEST_INT); +extern void lto_output_sleb128_stream (struct lto_output_stream *, + HOST_WIDE_INT); +extern bool lto_output_decl_index (struct lto_output_stream *, + struct lto_tree_ref_encoder *, + tree, unsigned int *); +extern void lto_output_field_decl_index (struct lto_out_decl_state *, + struct lto_output_stream *, tree); +extern void lto_output_fn_decl_index (struct lto_out_decl_state *, + struct lto_output_stream *, tree); +extern void lto_output_namespace_decl_index (struct lto_out_decl_state *, + struct lto_output_stream *, tree); +extern void lto_output_var_decl_index (struct lto_out_decl_state *, + struct lto_output_stream *, tree); +extern void lto_output_type_decl_index (struct lto_out_decl_state *, + struct lto_output_stream *, tree); +extern void lto_output_type_ref_index (struct lto_out_decl_state *, + struct lto_output_stream *, tree); +extern struct lto_simple_output_block *lto_create_simple_output_block ( + enum lto_section_type); +extern void lto_destroy_simple_output_block (struct lto_simple_output_block *); +extern struct lto_out_decl_state *lto_new_out_decl_state (void); +extern void lto_delete_out_decl_state (struct lto_out_decl_state *); +extern struct lto_out_decl_state *lto_get_out_decl_state (void); +extern void lto_push_out_decl_state (struct lto_out_decl_state *); +extern struct lto_out_decl_state *lto_pop_out_decl_state (void); +extern void lto_record_function_out_decl_state (tree, + struct lto_out_decl_state *); +extern void lto_new_extern_inline_states (void); +extern void lto_delete_extern_inline_states (void); +extern void lto_force_functions_extern_inline (bitmap decls); +extern bool lto_forced_extern_inline_p (tree fn_decl); + + +/* In lto-streamer.c. */ +extern const char *lto_tag_name (enum LTO_tags); +extern bitmap lto_bitmap_alloc (void); +extern void lto_bitmap_free (bitmap); +extern char *lto_get_section_name (int, const char *); +extern void print_lto_report (void); +extern struct bitpack_d *bitpack_create (void); +extern void bitpack_delete (struct bitpack_d *); +extern void bp_pack_value (struct bitpack_d *, bitpack_word_t, unsigned); +extern bitpack_word_t bp_unpack_value (struct bitpack_d *, unsigned); +extern bool lto_streamer_cache_insert (struct lto_streamer_cache_d *, tree, + int *, unsigned *); +extern bool lto_streamer_cache_insert_at (struct lto_streamer_cache_d *, tree, + int); +extern bool lto_streamer_cache_lookup (struct lto_streamer_cache_d *, tree, + int *); +extern tree lto_streamer_cache_get (struct lto_streamer_cache_d *, int); +extern struct lto_streamer_cache_d *lto_streamer_cache_create (void); +extern void lto_streamer_cache_delete (struct lto_streamer_cache_d *); +extern void lto_streamer_init (void); +extern bool gate_lto_out (void); +#ifdef LTO_STREAMER_DEBUG +extern void lto_orig_address_map (tree, intptr_t); +extern intptr_t lto_orig_address_get (tree); +extern void lto_orig_address_remove (tree); +#endif +extern void lto_check_version (int, int); + + +/* In lto-streamer-in.c */ +extern void lto_input_cgraph (struct lto_file_decl_data *, const char *); +extern void lto_init_reader (void); +extern tree lto_input_tree (struct lto_input_block *, struct data_in *); +extern void lto_input_function_body (struct lto_file_decl_data *, tree, + const char *); +extern void lto_input_constructors_and_inits (struct lto_file_decl_data *, + const char *); +extern struct bitpack_d *lto_input_bitpack (struct lto_input_block *); +extern void lto_init_reader (void); +extern struct data_in *lto_data_in_create (struct lto_file_decl_data *, + const char *, unsigned, + VEC(ld_plugin_symbol_resolution_t,heap) *); +extern void lto_data_in_delete (struct data_in *); + + +/* In lto-streamer-out.c */ +extern void lto_register_decl_definition (tree, struct lto_file_decl_data *); +extern struct output_block *create_output_block (enum lto_section_type); +extern void destroy_output_block (struct output_block *); +extern void lto_output_tree (struct output_block *, tree, bool); +extern void lto_output_bitpack (struct lto_output_stream *, struct bitpack_d *); +extern void produce_asm (struct output_block *ob, tree fn); + + +/* In lto-cgraph.c */ +struct cgraph_node *lto_cgraph_encoder_deref (lto_cgraph_encoder_t, int); +int lto_cgraph_encoder_lookup (lto_cgraph_encoder_t, struct cgraph_node *); +lto_cgraph_encoder_t lto_cgraph_encoder_new (void); +int lto_cgraph_encoder_encode (lto_cgraph_encoder_t, struct cgraph_node *); +void lto_cgraph_encoder_delete (lto_cgraph_encoder_t encoder); +void output_cgraph (cgraph_node_set); +void input_cgraph (void); + + +/* In lto-symtab.c. */ +extern void lto_symtab_register_decl (tree, ld_plugin_symbol_resolution_t, + struct lto_file_decl_data *); +extern void lto_symtab_merge_decls (void); +extern void lto_symtab_merge_cgraph_nodes (void); +extern tree lto_symtab_prevailing_decl (tree decl); +extern enum ld_plugin_symbol_resolution lto_symtab_get_resolution (tree decl); + + +/* In lto-opts.c. */ +extern void lto_register_user_option (size_t, const char *, int, int); +extern void lto_read_file_options (struct lto_file_decl_data *); +extern void lto_write_options (void); +extern void lto_reissue_options (void); +void lto_clear_user_options (void); +void lto_clear_file_options (void); + + +/* In lto-wpa-fixup.c */ +void lto_mark_nothrow_fndecl (tree); +void lto_fixup_nothrow_decls (void); + + +/* Statistics gathered during LTO, WPA and LTRANS. */ +extern struct lto_stats_d lto_stats; + +/* Section names corresponding to the values of enum lto_section_type. */ +extern const char *lto_section_name[]; + +/* Holds all the out decl states of functions output so far in the + current output file. */ +extern VEC(lto_out_decl_state_ptr, heap) *lto_function_decl_states; + +/* Return true if LTO tag TAG corresponds to a tree code. */ +static inline bool +lto_tag_is_tree_code_p (enum LTO_tags tag) +{ + return tag > LTO_null && (unsigned) tag <= NUM_TREE_CODES; +} + + +/* Return true if LTO tag TAG corresponds to a gimple code. */ +static inline bool +lto_tag_is_gimple_code_p (enum LTO_tags tag) +{ + return (unsigned) tag >= NUM_TREE_CODES + 1 + && (unsigned) tag < 1 + NUM_TREE_CODES + LAST_AND_UNUSED_GIMPLE_CODE; +} + + +/* Return the LTO tag corresponding to gimple code CODE. See enum + LTO_tags for details on the conversion. */ +static inline enum LTO_tags +lto_gimple_code_to_tag (enum gimple_code code) +{ + return (enum LTO_tags) ((unsigned) code + NUM_TREE_CODES + 1); +} + + +/* Return the GIMPLE code corresponding to TAG. See enum LTO_tags for + details on the conversion. */ +static inline enum gimple_code +lto_tag_to_gimple_code (enum LTO_tags tag) +{ + gcc_assert (lto_tag_is_gimple_code_p (tag)); + return (enum gimple_code) ((unsigned) tag - NUM_TREE_CODES - 1); +} + + +/* Return the LTO tag corresponding to tree code CODE. See enum + LTO_tags for details on the conversion. */ +static inline enum LTO_tags +lto_tree_code_to_tag (enum tree_code code) +{ + return (enum LTO_tags) ((unsigned) code + 1); +} + + +/* Return the tree code corresponding to TAG. See enum LTO_tags for + details on the conversion. */ +static inline enum tree_code +lto_tag_to_tree_code (enum LTO_tags tag) +{ + gcc_assert (lto_tag_is_tree_code_p (tag)); + return (enum tree_code) ((unsigned) tag - 1); +} + + +/* Return true if FILE needs to be compiled with LTRANS. */ +static inline bool +lto_file_needs_ltrans_p (struct lto_file_decl_data *file) +{ + return file->needs_ltrans_p != 0; +} + + +/* Mark FILE to be compiled with LTRANS. */ +static inline void +lto_mark_file_for_ltrans (struct lto_file_decl_data *file) +{ + file->needs_ltrans_p = 1; +} + + +/* Return true if any files in node set SET need to be compiled + with LTRANS. */ +static inline bool +cgraph_node_set_needs_ltrans_p (cgraph_node_set set) +{ + cgraph_node_set_iterator csi; + + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + if (lto_file_needs_ltrans_p (csi_node (csi)->local.lto_file_data)) + return true; + + return false; +} + + +/* Initialize an lto_out_decl_buffer ENCODER. */ +static inline void +lto_init_tree_ref_encoder (struct lto_tree_ref_encoder *encoder, + htab_hash hash_fn, htab_eq eq_fn) +{ + encoder->tree_hash_table = htab_create (37, hash_fn, eq_fn, free); + encoder->next_index = 0; + encoder->trees = NULL; +} + + +/* Destory an lto_tree_ref_encoder ENCODER by freeing its contents. The + memory used by ENCODER is not freed by this function. */ +static inline void +lto_destroy_tree_ref_encoder (struct lto_tree_ref_encoder *encoder) +{ + /* Hash table may be delete already. */ + if (encoder->tree_hash_table) + htab_delete (encoder->tree_hash_table); + VEC_free (tree, heap, encoder->trees); +} + +/* Return the number of trees encoded in ENCODER. */ +static inline unsigned int +lto_tree_ref_encoder_size (struct lto_tree_ref_encoder *encoder) +{ + return VEC_length (tree, encoder->trees); +} + +/* Return the IDX-th tree in ENCODER. */ +static inline tree +lto_tree_ref_encoder_get_tree (struct lto_tree_ref_encoder *encoder, + unsigned int idx) +{ + return VEC_index (tree, encoder->trees, idx); +} + + +/* Return true if LABEL should be emitted in the global context. */ +static inline bool +emit_label_in_global_context_p (tree label) +{ + return DECL_NONLOCAL (label) || FORCED_LABEL (label); +} + +/* Return true if tree node EXPR should be streamed as a builtin. For + these nodes, we just emit the class and function code. */ +static inline bool +lto_stream_as_builtin_p (tree expr) +{ + return (TREE_CODE (expr) == FUNCTION_DECL + && DECL_IS_BUILTIN (expr) + && (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL + || DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD)); +} + +/* Return true if EXPR is a tree node that can be written to disk. */ +static inline bool +lto_is_streamable (tree expr) +{ + enum tree_code code = TREE_CODE (expr); + + /* Notice that we reject SSA_NAMEs as well. We only emit the SSA + name version in lto_output_tree_ref (see output_ssa_names). */ + return !is_lang_specific (expr) + && code != SSA_NAME + && code != CALL_EXPR + && code != LANG_TYPE + && code != MODIFY_EXPR + && code != INIT_EXPR + && code != TARGET_EXPR + && code != BIND_EXPR + && code != WITH_CLEANUP_EXPR + && code != STATEMENT_LIST + && (code == CASE_LABEL_EXPR + || code == DECL_EXPR + || TREE_CODE_CLASS (code) != tcc_statement); +} + +DEFINE_DECL_STREAM_FUNCS (TYPE, type) +DEFINE_DECL_STREAM_FUNCS (FIELD_DECL, field_decl) +DEFINE_DECL_STREAM_FUNCS (FN_DECL, fn_decl) +DEFINE_DECL_STREAM_FUNCS (VAR_DECL, var_decl) +DEFINE_DECL_STREAM_FUNCS (TYPE_DECL, type_decl) +DEFINE_DECL_STREAM_FUNCS (NAMESPACE_DECL, namespace_decl) +DEFINE_DECL_STREAM_FUNCS (LABEL_DECL, label_decl) + +#endif /* GCC_LTO_STREAMER_H */ diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c new file mode 100644 index 00000000000..642b6235d90 --- /dev/null +++ b/gcc/lto-symtab.c @@ -0,0 +1,676 @@ +/* LTO symbol table. + Copyright 2009 Free Software Foundation, Inc. + Contributed by CodeSourcery, 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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "toplev.h" +#include "tree.h" +#include "gimple.h" +#include "ggc.h" /* lambda.h needs this */ +#include "lambda.h" /* gcd */ +#include "hashtab.h" +#include "plugin-api.h" +#include "lto-streamer.h" + +/* Vector to keep track of external variables we've seen so far. */ +VEC(tree,gc) *lto_global_var_decls; + +/* Symbol table entry. */ + +struct GTY(()) lto_symtab_entry_def +{ + /* The symbol table entry key, an IDENTIFIER. */ + tree id; + /* The symbol table entry, a DECL. */ + tree decl; + /* The cgraph node if decl is a function decl. Filled in during the + merging process. */ + struct cgraph_node *node; + /* LTO file-data and symbol resolution for this decl. */ + struct lto_file_decl_data * GTY((skip (""))) file_data; + enum ld_plugin_symbol_resolution resolution; + /* Pointer to the next entry with the same key. Before decl merging + this links all symbols from the different TUs. After decl merging + this links merged but incompatible decls, thus all prevailing ones + remaining. */ + struct lto_symtab_entry_def *next; +}; +typedef struct lto_symtab_entry_def *lto_symtab_entry_t; + +/* A poor man's symbol table. This hashes identifier to prevailing DECL + if there is one. */ + +static GTY ((if_marked ("lto_symtab_entry_marked_p"), + param_is (struct lto_symtab_entry_def))) + htab_t lto_symtab_identifiers; + +/* Return the hash value of an lto_symtab_entry_t object pointed to by P. */ + +static hashval_t +lto_symtab_entry_hash (const void *p) +{ + const struct lto_symtab_entry_def *base = + (const struct lto_symtab_entry_def *) p; + return htab_hash_string (IDENTIFIER_POINTER (base->id)); +} + +/* Return non-zero if P1 and P2 points to lto_symtab_entry_def structs + corresponding to the same symbol. */ + +static int +lto_symtab_entry_eq (const void *p1, const void *p2) +{ + const struct lto_symtab_entry_def *base1 = + (const struct lto_symtab_entry_def *) p1; + const struct lto_symtab_entry_def *base2 = + (const struct lto_symtab_entry_def *) p2; + return (base1->id == base2->id); +} + +/* Returns non-zero if P points to an lto_symtab_entry_def struct that needs + to be marked for GC. */ + +static int +lto_symtab_entry_marked_p (const void *p) +{ + const struct lto_symtab_entry_def *base = + (const struct lto_symtab_entry_def *) p; + + /* Keep this only if the decl or the chain is marked. */ + return (ggc_marked_p (base->decl) + || (base->next && ggc_marked_p (base->next))); +} + +/* Lazily initialize resolution hash tables. */ + +static void +lto_symtab_maybe_init_hash_table (void) +{ + if (lto_symtab_identifiers) + return; + + lto_symtab_identifiers = + htab_create_ggc (1021, lto_symtab_entry_hash, + lto_symtab_entry_eq, NULL); +} + +/* Registers DECL with the LTO symbol table as having resolution RESOLUTION + and read from FILE_DATA. */ + +void +lto_symtab_register_decl (tree decl, + ld_plugin_symbol_resolution_t resolution, + struct lto_file_decl_data *file_data) +{ + lto_symtab_entry_t new_entry; + void **slot; + + /* Check that declarations reaching this function do not have + properties inconsistent with having external linkage. If any of + these asertions fail, then the object file reader has failed to + detect these cases and issue appropriate error messages. */ + gcc_assert (decl + && TREE_PUBLIC (decl) + && (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL) + && DECL_ASSEMBLER_NAME_SET_P (decl)); + if (TREE_CODE (decl) == VAR_DECL + && DECL_INITIAL (decl)) + gcc_assert (!DECL_EXTERNAL (decl) + || (TREE_STATIC (decl) && TREE_READONLY (decl))); + if (TREE_CODE (decl) == FUNCTION_DECL) + gcc_assert (!DECL_ABSTRACT (decl)); + + new_entry = GGC_CNEW (struct lto_symtab_entry_def); + new_entry->id = DECL_ASSEMBLER_NAME (decl); + new_entry->decl = decl; + new_entry->resolution = resolution; + new_entry->file_data = file_data; + + lto_symtab_maybe_init_hash_table (); + slot = htab_find_slot (lto_symtab_identifiers, new_entry, INSERT); + new_entry->next = (lto_symtab_entry_t) *slot; + *slot = new_entry; +} + +/* Get the lto_symtab_entry_def struct associated with ID + if there is one. */ + +static lto_symtab_entry_t +lto_symtab_get (tree id) +{ + struct lto_symtab_entry_def temp; + void **slot; + + lto_symtab_maybe_init_hash_table (); + temp.id = id; + slot = htab_find_slot (lto_symtab_identifiers, &temp, NO_INSERT); + return slot ? (lto_symtab_entry_t) *slot : NULL; +} + +/* Get the linker resolution for DECL. */ + +enum ld_plugin_symbol_resolution +lto_symtab_get_resolution (tree decl) +{ + lto_symtab_entry_t e; + + gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); + + e = lto_symtab_get (DECL_ASSEMBLER_NAME (decl)); + while (e && e->decl != decl) + e = e->next; + if (!e) + return LDPR_UNKNOWN; + + return e->resolution; +} + + +/* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging + all edges and removing the old node. */ + +static void +lto_cgraph_replace_node (struct cgraph_node *node, + struct cgraph_node *prevailing_node) +{ + struct cgraph_edge *e, *next; + + /* Merge node flags. */ + if (node->needed) + cgraph_mark_needed_node (prevailing_node); + if (node->reachable) + cgraph_mark_reachable_node (prevailing_node); + if (node->address_taken) + { + gcc_assert (!prevailing_node->global.inlined_to); + cgraph_mark_address_taken_node (prevailing_node); + } + + /* Redirect all incoming edges. */ + for (e = node->callers; e; e = next) + { + next = e->next_caller; + cgraph_redirect_edge_callee (e, prevailing_node); + } + + /* There are not supposed to be any outgoing edges from a node we + replace. Still this can happen for multiple instances of weak + functions. */ + for (e = node->callees; e; e = next) + { + next = e->next_callee; + cgraph_remove_edge (e); + } + + /* Finally remove the replaced node. */ + cgraph_remove_node (node); +} + +/* Merge two variable or function symbol table entries PREVAILING and ENTRY. + Return false if the symbols are not fully compatible and a diagnostic + should be emitted. */ + +static bool +lto_symtab_merge (lto_symtab_entry_t prevailing, lto_symtab_entry_t entry) +{ + tree prevailing_decl = prevailing->decl; + tree decl = entry->decl; + tree prevailing_type, type; + + /* Merge decl state in both directions, we may still end up using + the new decl. */ + TREE_ADDRESSABLE (prevailing_decl) |= TREE_ADDRESSABLE (decl); + TREE_ADDRESSABLE (decl) |= TREE_ADDRESSABLE (prevailing_decl); + + /* The linker may ask us to combine two incompatible symbols. + Detect this case and notify the caller of required diagnostics. */ + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (TREE_TYPE (prevailing_decl) != TREE_TYPE (decl)) + /* If we don't have a merged type yet...sigh. The linker + wouldn't complain if the types were mismatched, so we + probably shouldn't either. Just use the type from + whichever decl appears to be associated with the + definition. If for some odd reason neither decl is, the + older one wins. */ + (void) 0; + + return true; + } + + /* Now we exclusively deal with VAR_DECLs. */ + + /* Sharing a global symbol is a strong hint that two types are + compatible. We could use this information to complete + incomplete pointed-to types more aggressively here, ignoring + mismatches in both field and tag names. It's difficult though + to guarantee that this does not have side-effects on merging + more compatible types from other translation units though. */ + + /* We can tolerate differences in type qualification, the + qualification of the prevailing definition will prevail. + ??? In principle we might want to only warn for structurally + incompatible types here, but unless we have protective measures + for TBAA in place that would hide useful information. */ + prevailing_type = TYPE_MAIN_VARIANT (TREE_TYPE (prevailing_decl)); + type = TYPE_MAIN_VARIANT (TREE_TYPE (decl)); + + /* We have to register and fetch canonical types here as the global + fixup process didn't yet run. */ + prevailing_type = gimple_register_type (prevailing_type); + type = gimple_register_type (type); + if (prevailing_type != type) + { + if (COMPLETE_TYPE_P (type)) + return false; + + /* If type is incomplete then avoid warnings in the cases + that TBAA handles just fine. */ + + if (TREE_CODE (prevailing_type) != TREE_CODE (type)) + return false; + + if (TREE_CODE (prevailing_type) == ARRAY_TYPE) + { + tree tem1 = TREE_TYPE (prevailing_type); + tree tem2 = TREE_TYPE (type); + while (TREE_CODE (tem1) == ARRAY_TYPE + && TREE_CODE (tem2) == ARRAY_TYPE) + { + tem1 = TREE_TYPE (tem1); + tem2 = TREE_TYPE (tem2); + } + + if (TREE_CODE (tem1) != TREE_CODE (tem2)) + return false; + + if (gimple_register_type (tem1) != gimple_register_type (tem2)) + return false; + } + + /* Fallthru. Compatible enough. */ + } + + /* ??? We might want to emit a warning here if type qualification + differences were spotted. Do not do this unconditionally though. */ + + /* There is no point in comparing too many details of the decls here. + The type compatibility checks or the completing of types has properly + dealt with most issues. */ + + /* The following should all not invoke fatal errors as in non-LTO + mode the linker wouldn't complain either. Just emit warnings. */ + + /* Report a warning if user-specified alignments do not match. */ + if ((DECL_USER_ALIGN (prevailing_decl) && DECL_USER_ALIGN (decl)) + && DECL_ALIGN (prevailing_decl) < DECL_ALIGN (decl)) + return false; + + return true; +} + +/* Return true if the symtab entry E can be replaced by another symtab + entry. */ + +static bool +lto_symtab_resolve_replaceable_p (lto_symtab_entry_t e) +{ + if (DECL_EXTERNAL (e->decl) + || DECL_COMDAT (e->decl) + || DECL_WEAK (e->decl)) + return true; + + if (TREE_CODE (e->decl) == VAR_DECL) + return (DECL_COMMON (e->decl) + || (!flag_no_common && !DECL_INITIAL (e->decl))); + + return false; +} + +/* Return true if the symtab entry E can be the prevailing one. */ + +static bool +lto_symtab_resolve_can_prevail_p (lto_symtab_entry_t e) +{ + if (!TREE_STATIC (e->decl)) + return false; + + /* For functions we need a non-discarded body. */ + if (TREE_CODE (e->decl) == FUNCTION_DECL) + return (e->node && e->node->analyzed); + + /* A variable should have a size. */ + else if (TREE_CODE (e->decl) == VAR_DECL) + return (DECL_SIZE (e->decl) != NULL_TREE + /* The C++ frontend retains TREE_STATIC on the declaration + of foo_ in struct Foo { static Foo *foo_; }; but it is + not a definition. g++.dg/lto/20090315_0.C. */ + && !DECL_EXTERNAL (e->decl)); + + gcc_unreachable (); +} + +/* Resolve the symbol with the candidates in the chain *SLOT and store + their resolutions. */ + +static void +lto_symtab_resolve_symbols (void **slot) +{ + lto_symtab_entry_t e = (lto_symtab_entry_t) *slot; + lto_symtab_entry_t prevailing = NULL; + + /* If the chain is already resolved there is nothing to do. */ + if (e->resolution != LDPR_UNKNOWN) + return; + + /* Find the single non-replaceable prevailing symbol and + diagnose ODR violations. */ + for (; e; e = e->next) + { + if (TREE_CODE (e->decl) == FUNCTION_DECL) + e->node = cgraph_get_node (e->decl); + + if (!lto_symtab_resolve_can_prevail_p (e)) + { + e->resolution = LDPR_RESOLVED_IR; + continue; + } + + /* Set a default resolution - the final prevailing one will get + adjusted later. */ + e->resolution = LDPR_PREEMPTED_IR; + if (!lto_symtab_resolve_replaceable_p (e)) + { + if (prevailing) + { + error_at (DECL_SOURCE_LOCATION (e->decl), + "%qD has already been defined", e->decl); + inform (DECL_SOURCE_LOCATION (prevailing->decl), + "previously defined here"); + } + prevailing = e; + } + } + if (prevailing) + goto found; + + /* Do a second round choosing one from the replaceable prevailing decls. */ + for (e = (lto_symtab_entry_t) *slot; e; e = e->next) + { + if (e->resolution != LDPR_PREEMPTED_IR) + continue; + + /* Choose the first function that can prevail as prevailing. */ + if (TREE_CODE (e->decl) == FUNCTION_DECL) + { + prevailing = e; + break; + } + + /* From variables that can prevail choose the largest one. */ + if (!prevailing + || tree_int_cst_lt (DECL_SIZE (prevailing->decl), + DECL_SIZE (e->decl))) + prevailing = e; + } + + if (!prevailing) + return; + +found: + if (TREE_CODE (prevailing->decl) == VAR_DECL + && TREE_READONLY (prevailing->decl)) + prevailing->resolution = LDPR_PREVAILING_DEF_IRONLY; + else + prevailing->resolution = LDPR_PREVAILING_DEF; +} + +/* Merge all decls in the symbol table chain to the prevailing decl and + issue diagnostics about type mismatches. */ + +static void +lto_symtab_merge_decls_2 (void **slot) +{ + lto_symtab_entry_t prevailing, e; + VEC(tree, heap) *mismatches = NULL; + unsigned i; + tree decl; + bool diagnosed_p = false; + + /* Nothing to do for a single entry. */ + prevailing = (lto_symtab_entry_t) *slot; + if (!prevailing->next) + return; + + /* Try to merge each entry with the prevailing one. */ + for (e = prevailing->next; e; e = e->next) + { + if (!lto_symtab_merge (prevailing, e)) + VEC_safe_push (tree, heap, mismatches, e->decl); + } + if (VEC_empty (tree, mismatches)) + return; + + /* Diagnose all mismatched re-declarations. */ + for (i = 0; VEC_iterate (tree, mismatches, i, decl); ++i) + { + if (TREE_TYPE (prevailing->decl) != TREE_TYPE (decl)) + diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, + "type of %qD does not match original " + "declaration", decl); + + else if ((DECL_USER_ALIGN (prevailing->decl) && DECL_USER_ALIGN (decl)) + && DECL_ALIGN (prevailing->decl) < DECL_ALIGN (decl)) + { + diagnosed_p |= warning_at (DECL_SOURCE_LOCATION (decl), 0, + "alignment of %qD is bigger than " + "original declaration", decl); + } + } + if (diagnosed_p) + inform (DECL_SOURCE_LOCATION (prevailing->decl), + "previously declared here"); + + VEC_free (tree, heap, mismatches); +} + +/* Helper to process the decl chain for the symbol table entry *SLOT. */ + +static int +lto_symtab_merge_decls_1 (void **slot, void *data ATTRIBUTE_UNUSED) +{ + lto_symtab_entry_t e, prevailing; + bool diagnosed_p = false; + + /* Compute the symbol resolutions. This is a no-op when using the + linker plugin. */ + lto_symtab_resolve_symbols (slot); + + /* Find the prevailing decl. */ + for (prevailing = (lto_symtab_entry_t) *slot; + prevailing + && prevailing->resolution != LDPR_PREVAILING_DEF_IRONLY + && prevailing->resolution != LDPR_PREVAILING_DEF; + prevailing = prevailing->next) + ; + + /* Assert it's the only one. */ + if (prevailing) + for (e = prevailing->next; e; e = e->next) + gcc_assert (e->resolution != LDPR_PREVAILING_DEF_IRONLY + && e->resolution != LDPR_PREVAILING_DEF); + + /* If there's not a prevailing symbol yet it's an external reference. + Happens a lot during ltrans. Choose the first symbol with a + cgraph or a varpool node. */ + if (!prevailing) + { + prevailing = (lto_symtab_entry_t) *slot; + /* For functions choose one with a cgraph node. */ + if (TREE_CODE (prevailing->decl) == FUNCTION_DECL) + while (!prevailing->node + && prevailing->next) + prevailing = prevailing->next; + /* We do not stream varpool nodes, so the first decl has to + be good enough for now. + ??? For QOI choose a variable with readonly initializer + if there is one. This matches C++ + struct Foo { static const int i = 1; }; without a real + definition. */ + if (TREE_CODE (prevailing->decl) == VAR_DECL) + while (!(TREE_READONLY (prevailing->decl) + && DECL_INITIAL (prevailing->decl)) + && prevailing->next) + prevailing = prevailing->next; + } + + /* Move it first in the list. */ + if ((lto_symtab_entry_t) *slot != prevailing) + { + for (e = (lto_symtab_entry_t) *slot; e->next != prevailing; e = e->next) + ; + e->next = prevailing->next; + prevailing->next = (lto_symtab_entry_t) *slot; + *slot = (void *) prevailing; + } + + /* Record the prevailing variable. */ + if (TREE_CODE (prevailing->decl) == VAR_DECL) + VEC_safe_push (tree, gc, lto_global_var_decls, prevailing->decl); + + /* Diagnose mismatched objects. */ + for (e = prevailing->next; e; e = e->next) + { + if (TREE_CODE (prevailing->decl) == TREE_CODE (e->decl)) + continue; + + switch (TREE_CODE (prevailing->decl)) + { + case VAR_DECL: + gcc_assert (TREE_CODE (e->decl) == FUNCTION_DECL); + error_at (DECL_SOURCE_LOCATION (e->decl), + "variable %qD redeclared as function", prevailing->decl); + break; + + case FUNCTION_DECL: + gcc_assert (TREE_CODE (e->decl) == VAR_DECL); + error_at (DECL_SOURCE_LOCATION (e->decl), + "function %qD redeclared as variable", prevailing->decl); + break; + + default: + gcc_unreachable (); + } + + diagnosed_p = true; + } + if (diagnosed_p) + inform (DECL_SOURCE_LOCATION (prevailing->decl), + "previously declared here"); + + /* Register and adjust types of the entries. */ + for (e = (lto_symtab_entry_t) *slot; e; e = e->next) + TREE_TYPE (e->decl) = gimple_register_type (TREE_TYPE (e->decl)); + + /* Merge the chain to the single prevailing decl and diagnose + mismatches. */ + lto_symtab_merge_decls_2 (slot); + + /* Drop all but the prevailing decl from the symtab. */ + if (TREE_CODE (prevailing->decl) != FUNCTION_DECL) + prevailing->next = NULL; + + return 1; +} + +/* Resolve and merge all symbol table chains to a prevailing decl. */ + +void +lto_symtab_merge_decls (void) +{ + lto_symtab_maybe_init_hash_table (); + htab_traverse (lto_symtab_identifiers, lto_symtab_merge_decls_1, NULL); +} + +/* Helper to process the decl chain for the symbol table entry *SLOT. */ + +static int +lto_symtab_merge_cgraph_nodes_1 (void **slot, void *data ATTRIBUTE_UNUSED) +{ + lto_symtab_entry_t e, prevailing = (lto_symtab_entry_t) *slot; + + if (!prevailing->next) + return 1; + + gcc_assert (TREE_CODE (prevailing->decl) == FUNCTION_DECL); + + /* Replace the cgraph node of each entry with the prevailing one. */ + for (e = prevailing->next; e; e = e->next) + { + if (e->node != NULL) + lto_cgraph_replace_node (e->node, prevailing->node); + } + + /* Drop all but the prevailing decl from the symtab. */ + prevailing->next = NULL; + + return 1; +} + +/* Merge cgraph nodes according to the symbol merging done by + lto_symtab_merge_decls. */ + +void +lto_symtab_merge_cgraph_nodes (void) +{ + lto_symtab_maybe_init_hash_table (); + htab_traverse (lto_symtab_identifiers, lto_symtab_merge_cgraph_nodes_1, NULL); +} + +/* Given the decl DECL, return the prevailing decl with the same name. */ + +tree +lto_symtab_prevailing_decl (tree decl) +{ + lto_symtab_entry_t ret; + + /* Builtins and local symbols are their own prevailing decl. */ + if (!TREE_PUBLIC (decl) || is_builtin_fn (decl)) + return decl; + + /* DECL_ABSTRACTs are their own prevailng decl. */ + if (TREE_CODE (decl) == FUNCTION_DECL && DECL_ABSTRACT (decl)) + return decl; + + /* Ensure DECL_ASSEMBLER_NAME will not set assembler name. */ + gcc_assert (DECL_ASSEMBLER_NAME_SET_P (decl)); + + /* Walk through the list of candidates and return the one we merged to. */ + ret = lto_symtab_get (DECL_ASSEMBLER_NAME (decl)); + if (!ret) + return NULL_TREE; + + return ret->decl; +} + +#include "gt-lto-symtab.h" diff --git a/gcc/lto-wpa-fixup.c b/gcc/lto-wpa-fixup.c new file mode 100644 index 00000000000..4411588f2f3 --- /dev/null +++ b/gcc/lto-wpa-fixup.c @@ -0,0 +1,281 @@ +/* Write and read any fix-up information generated by the WPA mode. + + Copyright 2009 Free Software Foundation, Inc. + Contributed by Doug Kwan + +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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "tree.h" +#include "expr.h" +#include "flags.h" +#include "cgraph.h" +#include "function.h" +#include "diagnostic.h" +#include "vec.h" +#include "bitmap.h" +#include "timevar.h" +#include "tree-flow.h" +#include "tree-pass.h" +#include "lto-streamer.h" + +/* LTO fix-up. + + In WPA mode, LTO cannot access function bodies. Some modifications in + IR require additional updates in function bodies, which are not possible + in WPA mode. So we write out information about these modifications for + LTRANS to fix up the function bodies accordingly. */ + +/* The vectors records function DECLs having multiple copies with different + exception throwing attributes. We do not mark a DECL if all copies of it + have the same exception throwing attribute. */ +static bitmap lto_nothrow_fndecls; + +/* We need to fix up GIMPLE bodies due to changes in exception setting. + Consider this example: + + a.h: + class a { + public: + a(); + ~a(); + }; + + main.cc: + #include "a.h" + + int + main (int argc, char **argv) + { + a x; + return 0; + } + + a.cc: + #include "a.h" + a::a() {} + a::~a() {} + + When main.cc is compiled, gcc only sees the constructor declaration, so + the constructor and hence the call to it are marked as exception throwing. + When a.cc is compiled, the body of the constructor is available and is + obviously not exception throwing. Thus DECL of a::a in a.o has the NOTHROW + attribute. When LTO runs, two DECLs of a::a with different exception + attributes are merged. We want the merged DECL to be not exception + throwing for better generated code. To do that, we need to fix up any + function calls that have been marked as exception throwing. */ + +/* Fix up all the call statements whose target fndecls might have changed + to NOTHROW. Note that this problem is not WPA specific. We can also + run into this problem in normal LTO with multiple input files. */ + +void +lto_fixup_nothrow_decls (void) +{ + struct cgraph_node *node; + struct cgraph_edge *edge; + struct function *caller_function; + gimple call_stmt; + + /* Quit if we are in WPA mode or have not marked any DECLs. */ + if (flag_wpa || !lto_nothrow_fndecls) + return; + + /* For each node that has been marked, go over all call edges to it. */ + for (node = cgraph_nodes; node; node = node->next) + if (bitmap_bit_p (lto_nothrow_fndecls, DECL_UID (node->decl))) + { + gcc_assert (TREE_NOTHROW (node->decl)); + for (edge = node->callers; edge; edge = edge->next_caller) + { + caller_function = DECL_STRUCT_FUNCTION (edge->caller->decl); + call_stmt = edge->call_stmt; + gcc_assert (call_stmt); + if (lookup_stmt_eh_lp_fn (caller_function, call_stmt) != 0) + remove_stmt_from_eh_lp_fn (caller_function, call_stmt); + } + } +} + +/* Mark FNDECL as becoming not exception throwing. */ + +void +lto_mark_nothrow_fndecl (tree fndecl) +{ + gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL); + if (!lto_nothrow_fndecls) + lto_nothrow_fndecls = lto_bitmap_alloc (); + + bitmap_set_bit (lto_nothrow_fndecls, DECL_UID (fndecl)); +} + +/* Write out fix-up information. Currently the only WPA fix-up + information is the list of DECLs marked as not exception throwing. SET + is a cgraph node set whose fix-up information is to be written. */ + +static void +lto_output_wpa_fixup (cgraph_node_set set) +{ + struct lto_simple_output_block *ob; + cgraph_node_set_iterator csi; + tree fndecl; + bitmap seen_decls; + VEC(tree, heap) *decls = NULL; + unsigned HOST_WIDE_INT i, count; + + ob = lto_create_simple_output_block (LTO_section_wpa_fixup); + + /* Accumulate the DECLs to be written out. Since we do not want + duplicates, we need to use a bitmap and a vector to save the + DECLs we want. Note that we need to check if lto_nothrow_fndecls + is NULL. This happens when no DECL has been marked. */ + seen_decls = lto_bitmap_alloc (); + if (lto_nothrow_fndecls) + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + struct cgraph_edge *e; + struct cgraph_node *n; + + n = csi_node (csi); + fndecl = n->decl; + + /* Check if the N's function is in the set of nothrow functions. */ + if (!bitmap_bit_p (seen_decls, DECL_UID (fndecl))) + { + bitmap_set_bit (seen_decls, (DECL_UID (fndecl))); + if (bitmap_bit_p (lto_nothrow_fndecls, DECL_UID (fndecl))) + VEC_safe_push (tree, heap, decls, fndecl); + } + + /* Now check the callees and also add them if they are nothrow. This + is needed because node N may end up in a different partition than + its callees. In which case, when the file holding N is compiled, + the calls it makes to nothrow functions will not be fixed up, + causing verification issues. */ + for (e = n->callees; e; e = e->next_callee) + { + fndecl = e->callee->decl; + if (!bitmap_bit_p (seen_decls, DECL_UID (fndecl))) + { + bitmap_set_bit (seen_decls, (DECL_UID (fndecl))); + if (bitmap_bit_p (lto_nothrow_fndecls, DECL_UID (fndecl))) + VEC_safe_push (tree, heap, decls, fndecl); + } + } + } + + /* Write out number of DECLs, followed by the DECLs. */ + count = VEC_length (tree, decls); + lto_output_uleb128_stream (ob->main_stream, count); + for (i = 0; i < count; i++) + { + fndecl = VEC_index (tree, decls, i); + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, fndecl); + } + + /* Release resources. */ + lto_destroy_simple_output_block (ob); + VEC_free(tree, heap, decls); + lto_bitmap_free (seen_decls); +} + +/* Read in WPA fix-up information from one file. FILE_DATA points to + DECL information of the file where as IB is the input block for the + WPA fix-up section. */ + +static void +lto_input_wpa_fixup_1 (struct lto_file_decl_data *file_data, + struct lto_input_block *ib) +{ + unsigned HOST_WIDE_INT i, count, decl_index; + tree fndecl; + + count = lto_input_uleb128 (ib); + for (i = 0; i < count; i++) + { + decl_index = lto_input_uleb128 (ib); + fndecl = lto_file_decl_data_get_fn_decl (file_data, decl_index); + lto_mark_nothrow_fndecl (fndecl); + } +} + +/* Read in WPA fix-up information. */ + +static void +lto_input_wpa_fixup (void) +{ + struct lto_file_decl_data ** file_data_vec + = lto_get_file_decl_data (); + struct lto_file_decl_data * file_data; + int i = 0; + + /* Fix up information is only used in LTRANS mode. */ + if (!flag_ltrans) + return; + + while ((file_data = file_data_vec[i++])) + { + const char *data; + size_t len; + struct lto_input_block *ib + = lto_create_simple_input_block (file_data, LTO_section_wpa_fixup, + &data, &len); + + lto_input_wpa_fixup_1 (file_data, ib); + lto_destroy_simple_input_block (file_data, LTO_section_wpa_fixup, ib, + data, len); + } +} + +/* Gate function for all lto streaming passes. */ + +static bool +gate_wpa_fixup (void) +{ + return (flag_wpa || flag_ltrans) && gate_lto_out (); +} + +struct ipa_opt_pass_d pass_ipa_lto_wpa_fixup = +{ + { + IPA_PASS, + "lto_wpa_fixup", /* name */ + gate_wpa_fixup, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_WHOPR_WPA_FIXUP, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ + }, + NULL, /* generate_summary */ + lto_output_wpa_fixup, /* write_summary */ + lto_input_wpa_fixup, /* read_summary */ + NULL, /* function_read_summary */ + 0, /* TODOs */ + NULL, /* function_transform */ + NULL /* variable_transform */ +}; + diff --git a/gcc/lto-wrapper.c b/gcc/lto-wrapper.c new file mode 100644 index 00000000000..cddd4156a35 --- /dev/null +++ b/gcc/lto-wrapper.c @@ -0,0 +1,396 @@ +/* Wrapper to call lto. Used by collect2 and the linker plugin. + Copyright (C) 2009 Free Software Foundation, Inc. + + Factored out of collect2 by Rafael Espindola + +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 3, 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 COPYING3. If not see +. */ + + +/* This program is passed a gcc, a list of gcc arguments and a list of + object files containing IL. It scans the argument list to check if + we are in whopr mode or not modifies the arguments and needed and + prints a list of output files on stdout. + + Example: + + $ lto-wrapper gcc/xgcc -B gcc a.o b.o -o test -flto + + The above will print something like + /tmp/ccwbQ8B2.lto.o + + If -fwhopr is used instead, more than one file might be produced + ./ccXj2DTk.lto.ltrans.o + ./ccCJuXGv.lto.ltrans.o +*/ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "intl.h" +#include "libiberty.h" + +int debug; /* true if -debug */ + +enum lto_mode_d { + LTO_MODE_NONE, /* Not doing LTO. */ + LTO_MODE_LTO, /* Normal LTO. */ + LTO_MODE_WHOPR /* WHOPR. */ +}; + +/* Current LTO mode. */ +static enum lto_mode_d lto_mode = LTO_MODE_NONE; + +static char *ltrans_output_file; +static char *flto_out; +static char *args_name; + +static void maybe_unlink_file (const char *); + +/* Delete tempfiles and exit function. */ + +static void +lto_wrapper_exit (int status) +{ + if (ltrans_output_file) + maybe_unlink_file (ltrans_output_file); + if (flto_out) + maybe_unlink_file (flto_out); + if (args_name) + maybe_unlink_file (args_name); + exit (status); +} + +/* Just die. CMSGID is the error message. */ + +static void __attribute__ ((format (printf, 1, 2))) +fatal (const char * cmsgid, ...) +{ + va_list ap; + + va_start (ap, cmsgid); + fprintf (stderr, "lto-wrapper: "); + vfprintf (stderr, _(cmsgid), ap); + fprintf (stderr, "\n"); + va_end (ap); + + lto_wrapper_exit (FATAL_EXIT_CODE); +} + + +/* Die when sys call fails. CMSGID is the error message. */ + +static void __attribute__ ((format (printf, 1, 2))) +fatal_perror (const char *cmsgid, ...) +{ + int e = errno; + va_list ap; + + va_start (ap, cmsgid); + fprintf (stderr, "lto-wrapper: "); + vfprintf (stderr, _(cmsgid), ap); + fprintf (stderr, ": %s\n", xstrerror (e)); + va_end (ap); + + lto_wrapper_exit (FATAL_EXIT_CODE); +} + + +/* Execute a program, and wait for the reply. ARGV are the arguments. The + last one must be NULL. */ + +static struct pex_obj * +collect_execute (char **argv) +{ + struct pex_obj *pex; + const char *errmsg; + int err; + + if (debug) + { + char **p_argv; + const char *str; + + for (p_argv = argv; (str = *p_argv) != (char *) 0; p_argv++) + fprintf (stderr, " %s", str); + + fprintf (stderr, "\n"); + } + + fflush (stdout); + fflush (stderr); + + pex = pex_init (0, "lto-wrapper", NULL); + if (pex == NULL) + fatal_perror ("pex_init failed"); + + errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], argv, NULL, + NULL, &err); + if (errmsg != NULL) + { + if (err != 0) + { + errno = err; + fatal_perror (errmsg); + } + else + fatal (errmsg); + } + + return pex; +} + + +/* Wait for a process to finish, and exit if a nonzero status is found. + PROG is the program name. PEX is the process we should wait for. */ + +static int +collect_wait (const char *prog, struct pex_obj *pex) +{ + int status; + + if (!pex_get_status (pex, 1, &status)) + fatal_perror ("can't get program status"); + pex_free (pex); + + if (status) + { + if (WIFSIGNALED (status)) + { + int sig = WTERMSIG (status); + if (WCOREDUMP (status)) + fatal ("%s terminated with signal %d [%s], core dumped", + prog, sig, strsignal (sig)); + else + fatal ("%s terminated with signal %d [%s]", + prog, sig, strsignal (sig)); + } + + if (WIFEXITED (status)) + fatal ("%s returned %d exit status", prog, WEXITSTATUS (status)); + } + + return 0; +} + + +/* Unlink a temporary LTRANS file unless requested otherwise. */ + +static void +maybe_unlink_file (const char *file) +{ + if (! debug) + { + if (unlink_if_ordinary (file)) + fatal_perror ("deleting LTRANS file %s", file); + } + else + fprintf (stderr, "[Leaving LTRANS %s]\n", file); +} + + +/* Execute program ARGV[0] with arguments ARGV. Wait for it to finish. */ + +static void +fork_execute (char **argv) +{ + struct pex_obj *pex; + char *new_argv[3]; + char *at_args; + FILE *args; + int status; + + args_name = make_temp_file (".args"); + at_args = concat ("@", args_name, NULL); + args = fopen (args_name, "w"); + if (args == NULL) + fatal ("failed to open %s", args_name); + + status = writeargv (&argv[1], args); + + if (status) + fatal ("could not write to temporary file %s", args_name); + + fclose (args); + + new_argv[0] = argv[0]; + new_argv[1] = at_args; + new_argv[2] = NULL; + + pex = collect_execute (new_argv); + collect_wait (new_argv[0], pex); + + maybe_unlink_file (args_name); + free (at_args); +} + + +/* Execute gcc. ARGC is the number of arguments. ARGV contains the arguments. */ + +static void +run_gcc (unsigned argc, char *argv[]) +{ + unsigned i; + unsigned new_argc = argc; + const char **new_argv; + const char **argv_ptr; + char *list_option_full = NULL; + + new_argc += 8; + new_argv = (const char **) xcalloc (sizeof (char *), new_argc); + + argv_ptr = new_argv; + + *argv_ptr++ = argv[0]; + *argv_ptr++ = "-combine"; + *argv_ptr++ = "-x"; + *argv_ptr++ = "lto"; + *argv_ptr++ = "-c"; + if (lto_mode == LTO_MODE_LTO) + { + flto_out = make_temp_file (".lto.o"); + *argv_ptr++ = "-o"; + *argv_ptr++ = flto_out; + } + else if (lto_mode == LTO_MODE_WHOPR) + { + const char *list_option = "-fltrans-output-list="; + size_t list_option_len = strlen (list_option); + char *tmp; + + ltrans_output_file = make_temp_file (".ltrans.out"); + list_option_full = (char *) xmalloc (sizeof (char) * + (strlen (ltrans_output_file) + list_option_len + 1)); + tmp = list_option_full; + + *argv_ptr++ = tmp; + strcpy (tmp, list_option); + tmp += list_option_len; + strcpy (tmp, ltrans_output_file); + + *argv_ptr++ = "-fwpa"; + } + else + fatal ("invalid LTO mode"); + + /* Add inherited GCC options to the LTO back end command line. + Filter out some obviously inappropriate options that will + conflict with the options that we force above. We pass + all of the remaining options on to LTO, and let it complain + about any it doesn't like. Note that we invoke LTO via the + `gcc' driver, so the usual option processing takes place. + Except for `-flto' and `-fwhopr', we should only filter options that + are meaningful to `ld', lest an option go silently unclaimed. */ + for (i = 1; i < argc; i++) + { + const char *s = argv[i]; + + if (strcmp (s, "-flto") == 0 || strcmp (s, "-fwhopr") == 0) + /* We've handled this LTO option, don't pass it on. */ + ; + else if (*s == '-' && s[1] == 'o') + { + /* Drop `-o' and its filename argument. We will use a + temporary file for the LTO output. The `-o' option + will be interpreted by the linker. */ + if (s[2] == '\0') + i++; + } + else + /* Pass the option or argument to LTO. */ + *argv_ptr++ = s; + } + + *argv_ptr = NULL; + + fork_execute (CONST_CAST (char **, new_argv)); + free (new_argv); + new_argv = NULL; + + if (lto_mode == LTO_MODE_LTO) + { + printf("%s\n", flto_out); + free (flto_out); + flto_out = NULL; + } + else if (lto_mode == LTO_MODE_WHOPR) + { + FILE *stream = fopen (ltrans_output_file, "r"); + int c; + + if (!stream) + fatal_perror ("fopen: %s", ltrans_output_file); + + while ((c = getc (stream)) != EOF) + putc (c, stdout); + fclose (stream); + maybe_unlink_file (ltrans_output_file); + free (list_option_full); + } + else + fatal ("invalid LTO mode"); +} + + +/* Parse the command line. Copy any unused argument to GCC_ARGV. ARGC is the + number of arguments. ARGV contains the arguments. */ + +static int +process_args (int argc, char *argv[], char *gcc_argv[]) +{ + int i; + int j = 0; + + for (i = 1; i < argc; i ++) + { + if (! strcmp (argv[i], "-debug")) + debug = 1; + else if (! strcmp (argv[i], "-flto")) + lto_mode = LTO_MODE_LTO; + else if (! strcmp (argv[i], "-fwhopr")) + lto_mode = LTO_MODE_WHOPR; + else + { + gcc_argv[j] = argv[i]; + j++; + } + } + + return j; +} + + +/* Entry point. */ + +int +main (int argc, char *argv[]) +{ + char **gcc_argv; + int gcc_argc; + + gcc_init_libintl (); + + /* We may be called with all the arguments stored in some file and + passed with @file. Expand them into argv before processing. */ + expandargv (&argc, &argv); + gcc_argv = (char **) xcalloc (sizeof (char *), argc); + gcc_argc = process_args (argc, argv, gcc_argv); + run_gcc (gcc_argc, gcc_argv); + free (gcc_argv); + + return 0; +} diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog new file mode 100644 index 00000000000..3334de7eb95 --- /dev/null +++ b/gcc/lto/ChangeLog @@ -0,0 +1,2628 @@ +2009-11-04 Richard Guenther + Rafael Avila de Espindola + + * lto-elf.c (lto_elf_build_section_table): Add the base offset. + (lto_elf_file_open): Handle offsets in arguments name@offest. + +2009-10-30 Richard Guenther + + PR lto/41858 + * lto.c (lto_file_read): Do not set file_data->fd. + (lto_read_section_data): Use a single-entry file-descriptor cache. + Do not check the result of xmalloc. + (free_section_data): Do not use file_data->fd. + (lto_read_all_file_options): Likewise. + +2009-10-22 Richard Guenther + + * lto.c (lto_fixup_jump_functions): Remove. + (lto_fixup_decls): Do not fixup jump functions. + (read_cgraph_and_symbols): Schedule cgraph merging after + summary reading. Schedule type and decl fixup before + summary reading. + +2009-10-22 Richard Guenther + + * lto.c (lto_fixup_data_t): Remove free_list member. + (lto_fixup_tree): Do not insert into free_list. + (free_decl): Remove. + (lto_fixup_decls): Remove free-list handling. + +2009-10-22 Jan Hubicka + + * lto.c (lto_fixup_jump_functions): New function. + (lto_fixup_decls): Use it. + +2009-10-16 Richard Guenther + + PR lto/41715 + * lto.c (lto_fixup_tree): Revert last change. + +2009-10-14 Richard Guenther + + * lto.c (lto_fixup_tree): In case the prevailing decl is not + compatible with the one we replace wrap it around a + VIEW_CONVERT_EXPR. + +2009-10-09 Richard Guenther + + PR lto/41635 + PR lto/41636 + * lto.c (read_cgraph_and_symbols): Do not assert we can open + a file. + * lto-elf.c (init_shdr##BITS): Fix i18n problems. + (init_ehdr##BITS): Likewise. + +2009-10-08 Joseph Myers + + * lto-elf.c (init_shdr##BITS, lto_elf_begin_section_with_type, + init_ehdr##BITS, lto_elf_file_close): Remove trailing "." from + diagnostics. + * lto-lang.c (lto_post_options): Remove trailing "." from + diagnostics. + +2009-10-08 Richard Guenther + + * lto.c (read_cgraph_and_symbols): Free the gimple type merging + hash tables. + +2009-10-07 Joseph Myers + + * lto.c: Only include if HAVE_MMAP_FILE. + +2009-10-07 Jan Hubicka + + * lto.c (read_cgraph_and_symbols): Mark functions neccesary only at + ltrans stage; explain why this is needed and should not. + +2009-10-05 Richard Guenther + + PR lto/41552 + PR lto/41487 + * lto.c (lto_read_decls): Do not register deferred decls. + (read_cgraph_and_symbols): Delay symbol and cgraph merging + until after reading the IPA summaries. + +2009-10-02 Rafael Avila de Espindola + + * Make-lang.in (lto/lto-lang.o): Don't depend on lto/common.h. + (lto-lang.c): Don't include lto/common.h. + +2009-10-02 Rafael Avila de Espindola + + * Make-lang.in (LTO_OBJS): Remove lto/common.o. + (lto/common.o): Remove. + * common.c: Remove. + * common.h (lto_kind_str): Remove. + (lto_visibility_str): Remove. + (lto_resolution_str): Make it static. + +2009-10-01 Diego Novillo + + * lto.c (lto_read_decls): Add comment. + Call internal_error instead of gcc_assert. + (lto_resolution_read): Likewise. + (lto_add_all_inlinees): Tidy. + * Make-lang.in: Fix copyright boilerplate. + (lto.pdf): New. + (lto.install-pdf): New. + * lto-tree.h: Fix copyright boilerplate. + * lang-specs.h: Likewise. + Remove ".lto" entry from compilers fragment. + * lto-elf.c: Move inclusion of gelf.h after config.h. + Tidy formatting everywhere. + * lto.h: Fix copyright boilerplate. + Tidy formatting everywhere. + * common.c: Likewise. + * config-lang.in: Likewise. + * common.h: Likewise. + * lto-lang.c: Likewise. + +2009-10-01 Richard Guenther + + * lto.c (lto_read_section_data): Use plain lseek/read. + +2009-10-01 Richard Guenther + + * lto.c (LTO_MMAP_IO): Define if we can mmap files and + use sysconf to query the system page size. + (lto_file_read): Implement fallback using stdio. + (free_section_data): Likewise. + +2009-09-29 Diego Novillo + + * lto-lang.c (lto_init): Really fix call to + build_common_builtin_nodes. + +2009-09-29 Diego Novillo + + * lto-lang.c (lto_init): Fix call to + build_common_builtin_nodes. + +2009-09-29 Richard Guenther + + PR lto/40754 + * lto-elf.c (init_shdr##BITS): Properly specify alignment + in bytes. + (first_data_block): New static variable. + (lto_elf_append_data): Align the first data block in each + section. + +2009-09-28 Diego Novillo + + * lto-lang.c: Tidy. Remove stale FIXME lto markers. + * lto.c (strip_extension): New. + (get_filename_for_set): Call it. Do not call make_cwd_temp_file. + (lto_execute_ltrans): Tidy. + Do not pass -fwpa nor -fltrans-* to LTRANS. + * opts.c: Tidy formatting and remove stale FIXME lto markers. + * tree.c (need_assembler_name_p): Call + lang_hooks.decls.may_need_assembler_name_p if set. + * varasm.c (default_binds_local_p_1): Remove check for + flag_ltrans. + * varpool.c (decide_is_variable_needed): Do not test for + in_lto_p. + +2009-09-22 Richard Guenther + + PR lto/39276 + * lto.c (lto_execute_ltrans): Perform ltrans phase manually. + * Make-lang.in: Remove ltrans-driver stuff. + * config-lang.in: Likewise. + * lang.opt (fltrans-driver): Remove. + * lto-lang.c (lto_init_options): Remove code initializing + ltrans_driver. + * ltrans-driver: Remove. + +2009-09-21 Diego Novillo + + * lto-lang.c (lto_define_builtins): Remove superfluous + calls to targetm.init_builtins and build_common_builtin_nodes. + (lto_init): Add targetm.arm_eabi_unwinder as parameter to + build_common_builtin_nodes. + * lto.c (lto_materialize_function): Do nothing if NODE is a + clone. + +2009-09-03 Diego Novillo + + * lto-elf.c (validate_file): Replace call to + elf_getshstrndx with call to elf_getshdrstrndx. + +2009-08-19 Richard Guenther + + * lto-lang.c (lto_init): Merge char_type_node with the + appropriately signed variant. + +2009-08-19 Richard Guenther + + PR lto/41071 + * lto.c (lto_fixup_common): Re-build the pointer-to chain part one. + (lto_fixup_type): Re-build the pointer-to chain part two. + +2009-08-19 Richard Guenther + + PR lto/41071 + * lto.c (lto_fixup_type): Re-build the type variant chain. + +2009-08-19 Richard Guenther + + PR lto/41071 + * lto.c (lto_fixup_constructor): New function. + (lto_fixup_tree): Replace all types. Properly fixup + constructors and constants. + +2009-08-14 Richard Guenther + + * lto.c (read_cgraph_and_symbols): Exchange TREE_CHAIN use + for DECL_LANG_SPECIFIC. + +2009-08-13 Richard Guenther + + PR lto/41032 + * lto-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Define to NULL. + +2009-07-30 Richard Guenther + + PR lto/40903 + * lto.c (read_cgraph_and_symbols): After fixing up decls choose + the largest decl for output and free TREE_CHAIN for further + use. + +2009-07-24 Diego Novillo + + * Make-lang.in: Add empty lto.install-plugin target. + +2009-07-13 Diego Novillo + + * lto.c (lto_fixup_tree): Handle IMPORTED_DECL. + +2009-07-11 Richard Guenther + + * lto-lang.c (lto_write_globals): Wrapup global decls. + +2009-07-10 Richard Guenther + + * lto-lang.c (lto_init): Allocate one more location to make + BUILTINS_LOCATION correct. + +2009-07-09 Rainer Orth + + * lto.c (free_section_data): Cast computed_offset to caddr_t. + +2009-07-06 Diego Novillo + + * lto.c (lto_fixup_type): Fixup TYPE_SIZE and + TYPE_SIZE_UNIT. + +2009-07-06 Diego Novillo + + * lto.c (preload_common_nodes): Remove. + (lto_read_in_decl_state): Call lto_streamer_cache_get. + (lto_read_decls): Call lto_data_in_create and + lto_data_in_delete. + (free_decl): Do not call ggc_free. + (lto_main): Call lto_init_reader. + * lto-lang.c (lto_type_for_size): Handle intTI_type_node. + (lto_init): Initialize main_identifier_node if needed. + Make ptrdiff_type_node be integer_type_node. + +2009-06-19 Diego Novillo + + * lto.c: Remove code guarded by #ifdef LTO_STREAM_DEBUGGING. + Remove code guarded by #ifdef GLOBAL_STREAMER_TRACE. + Remove code guarded by #ifdef LOCAL_TRACE. + +2009-06-18 Diego Novillo + + * lto.c: Update license to GPLv3. + * lto-elf.c: Likewise. + * common.c: Likewise. + * lto-lang.c: Likewise. + * lto.h: Remove superfluous include files. Update all + users. + +2009-06-17 Diego Novillo + + * lto.c (read_cgraph_and_symbols): Call input_cgraph. + +2009-06-02 Diego Novillo + + * lto.c (lto_1_to_1_map): Ignore nodes that have not been + read in. + (materialize_cgraph): Only materialize nodes that have a + representation on file. + +2009-06-01 Diego Novillo + + * lto-lang.c (lto_handle_option): Hanlde OPT_Wabi. + +2009-05-31 Diego Novillo + + * lto-lang.c (lto_type_for_mode): Handle all the modes + handled in c_common_type_for_mode. + +2009-05-21 Diego Novillo + + * lto-elf.c: Always include . + * config-lang.in (target_libs): Remove. + (build_by_default): Set to no. + +2009-05-15 Diego Novillo + + * lto.c (lto_materialize_function): Assert that DECL is + not a builtin. + (materialize_cgraph): Don't try to materialize builtin + functions. + * lto-section-out.c (write_symbol_vec): Do not write + builtin functions. + +2009-05-13 Diego Novillo + + * lto-lang.c (LANG_HOOKS_GET_ALIAS_SET): Define. + +2009-05-07 Diego Novillo + + * lto.c (lto_resolution_read): Add type casts for C++ warnings. + (LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE): Define. + (lto_fixup_type): Call it for TYPE_POINTER_TO, + TYPE_REFERENCE_TO, TYPE_CONTEXT and TYPE_CANONICAL. + (lto_fixup_tree): Call gimple_register_type when *TP is a + type. + (lto_main): Call bitmap_obstack_initialize. + +2009-04-22 Diego Novillo + + * lto.c (free_section_data): Tidy. + (lto_1_to_1_map): Tidy. + (lto_add_all_inlinees): Tidy. + (prefix_name_with_star): New. + (get_filename_for_set): New. + (lto_wpa_write_files): Call cgraph_node_set_needs_ltrans_p + to determine what cgraph node sets to write. + Call get_filename_for_set to compute temporary file + names. + (lto_execute_ltrans): Do not execute LTRANS on files with + names that start with '*'. + Move logic to execute LTRANS together so that LTRANS is + invoked only if there are any files to compile. + (do_whole_program_analysis): Only remove output files + that do not start with '*'. + +2009-04-06 Diego Novillo + + * lto-lang.c (lto_post_options): Set flag_excess_precision_cmdline. + * lto.c (read_cgraph_and_symbols): Set cgraph_function_flags_ready. + (lto_add_all_inlinees): Tidy. + +2009-03-26 Diego Novillo + + * lto.c: Include gimple.h. + (lto_read_in_decl_state): Call gimple_register_type for + every type in every stream. + (lto_fixup_common): Call gimple_register_type if T has a + type. + (do_whole_program_analysis): Call print_lto_report. + (lto_main): Call print_lto_report after cgraph_optimize. + * Make-lang.in (lto.o): Add dependency on GIMPLE_H. + +2009-03-24 Diego Novillo + + * Make-lang.in (lto-lang.o): Add dependency on TARGET_H and EXPR_H. + (lto.o): Add dependency on GIMPLE_H. + +2009-03-10 Simon Baldwin + + * lto.c (lto_read_all_file_options): Close any open file descriptor + contained in file_data before freeing. + +2009-02-24 Rafael Avila de Espindola + + * lto.c (lto_add_inline_clones): Don't add the master clone. Check + for a decl in the original bitmap, not a node. + (lto_add_all_inlinees): Remove original nodes that are not needed. + (lto_scan_statics_in_cgraph_node): Don't care if the node is the master. + +2009-02-24 Diego Novillo + + * lto.c (lto_materialize_function): Update + lto_stats.num_function_bodies. + (get_section_data): Initialize *LEN to 0. + (lto_1_to_1_map): Update lto_stats.num_cgraph_partitions. + (lto_wpa_write_files): Update lto_stats.num_cgraph_nodes. + Update lto_stats.num_output_files. + (read_cgraph_and_symbols): Update lto_stats.num_input_files. + (materialize_cgraph): Update lto_stats.num_input_cgraph_nodes. + (lto_main): Initialize lto_stats. + If flag_lto_report is set, call print_lto_report. + +2009-02-19 Diego Novillo + + Revert + + 2009-02-19 Rafael Avila de Espindola + + * lto.c (lto_add_inline_clones): Don't add the + master clone. Check for a decl in the original + bitmap, not a node. + (lto_add_all_inlinees): Remove original nodes + that are not needed. + (lto_scan_statics_in_cgraph_node): Don't care if + the node is the master. + (lto_promote_cross_file_statics): Use a new + context.seen_node_decls for each set + +2009-02-19 Rafael Avila de Espindola + + * lto.c (lto_add_inline_clones): Don't add the master clone. Check + for a decl in the original bitmap, not a node. + (lto_add_all_inlinees): Remove original nodes that are not needed. + (lto_scan_statics_in_cgraph_node): Don't care if the node is the master. + (lto_promote_cross_file_statics): Use a new context.seen_node_decls + for each set + +2009-02-18 Diego Novillo + + * lto.c (lto_wpa_write_files): Use timers TV_WHOPR_WPA + and TV_WHOPR_WPA_IO. + (lto_execute_ltrans): Use timer TV_WHOPR_WPA_LTRANS_EXEC. + (read_cgraph_and_symbols): Use timer TV_IPA_LTO_DECL_IO. + (materialize_cgraph): Use timer TV_IPA_LTO_GIMPLE_IO. + Use timer TV_WHOPR_WPA or TV_WHOPR_LTRANS or TV_LTO + depending on command line flags. + (do_whole_program_analysis): Use timer TV_WHOPR_WPA. + (lto_main): Remove timer uses. + +2009-02-18 Rafael Avila de Espindola + + * lto.c (lto_materialize_function): Don't set DECL_EXTERN to 0. + (lto_wpa_write_files): Update calls to renamed functions. + +2009-02-17 Diego Novillo + + PR 39203 + * lto-lang.c (lto_post_options): Disable -fwhole-program + when running LTRANS. + +2009-02-10 Diego Novillo + + * lto.c (read_cgraph_and_symbols): Fix comment. + +2009-02-10 Diego Novillo + + * lto.c (read_cgraph_and_symbols): Read options from all + IL files. + +2009-02-10 Diego Novillo + + * lto.c (read_cgraph_and_symbols): Factor out of lto_main. + (materialize_cgraph): Likewise. + (do_whole_program_analysis): Likewise. + (lto_main): Call read_cgraph_and_symbols, + materialize_cgraph and do_whole_program_analysis. + +2009-02-10 Simon Baldwin + + * lto.c: Include lto-opts.h. + * (lto_main): Clear file options at loop start, read any saved + options from the first file handled, and re-issue options. + * Makefile.in (lto.o): Add dependency on lto-opts.h. + +2009-02-02 Diego Novillo + + * lto.c (lto_main): Stop LTO_TIMER and use + TV_WHOPR_WPA_LTRANS_EXEC when launching LTRANS. + +2009-01-30 H.J. Lu + + PR lto/38995 + * lto-elf.c (init_shdr##BITS): Set the sh_addralign field + to POINTER_SIZE. + +2009-01-29 Ramana Radhakrishnan + + * Make-lang.in (LTO_EXE): Link with all + BACKENDLIBS and not only GMPLIBS + +2009-01-28 H.J. Lu + + PR bootstrap/38992 + * lto-elf.c: Include gelf.h instead of libelf.h. + (lto_elf_file_close): Replace elfx_update_shstrndx with + gelf_getehdr, elf_getscn, gelf_getshdr, gelf_update_shdr and + gelf_update_ehdr. + +2009-01-28 H.J. Lu + + PR middle-end/38996 + * lto-elf.c (DEFINE_INIT_EHDR): Initialize e_version. + +2009-01-26 Diego Novillo + + * lto-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Update. + +2009-01-26 Diego Novillo + + * lto-lang.c (lto_types_compatible_p): Move to gimple.c + and rename into gimple_types_compatible_p. + +2009-01-12 Rafael Avila de Espindola + + * lto-lang.c (lang_hooks): Remove the const qualifier. + +2009-01-06 Diego Novillo + + * ltrans-driver: Mark 'all' target as phony. + +2008-12-31 Diego Novillo + + * ltrans-driver: Execute a NOP action for target 'all'. + +2008-12-19 Diego Novillo + + * lto.c (lto_1_to_1_map): Tidy. + +2008-12-19 Diego Novillo + + * lto-elf.c (lto_elf_file_open): When FILENAME cannot + be opened, show its name. + * ltrans-driver: If $verbose is set, do not use parallelism. + +2008-12-17 Rafael Avila de Espindola + + * lto.c (lto_fixup_function): New. + (lto_fixup_tree): Call lto_fixup_function. + +2008-12-14 Doug Kwan + + * lto.c (lto_1_to_1_map): Create a cgraph node set for any global + variables if there is no function. + +2008-12-10 Simon Baldwin + + * ltrans-driver: Always run make in silent mode, to avoid make's + trace on stdout interfering with lto-wrapper output. + +2008-12-10 Doug Kwan + + * lto.c (lto_add_inline_clones): Do not force master clones of + inlined functions already in SET to be static inline. + +2008-12-04 Doug Kwan + + * lto.c (globalize_context_t): New type to store states in + globalization of cross-file statics. + (globalize_cross_file_statics): New. + (lto_scan_statics_in_ref_table): Walk tree to look for reachable + static decls that need to be fixed up. + (lto_scan_statics_in_cgraph_node): Change call interface to use + a globalize_context_t CONTEXT for all states used. + (lto_scan_statics_in_remaining_global_vars): New. + (lto_promote_cross_file_statics): Use new call interface of + LTO_SCAN_STATICS_IN_CGRAPH_NODE. Handle remaining externally + visible vars in the last set. + +2008-12-03 Diego Novillo + + * lto.c (lto_fixup_tree): Do not emit an error when + PREVAILING throw but T doesn't. + +2008-12-02 Doug Kwan + + * lto.c (lto_scan_statics_in_ref_table): New function factored out + from code in ... + (lto_scan_statics_in_cgraph_node): Handle both file-scope static + variables and functions. + (lto_promote_cross_file_statics): Rename bitmaps to SEEN_DECLS + and GLOBAL_DECLS from SEEN_VARS and GLOBAL_VARS. + +2008-11-29 Diego Novillo + + * lto.c: Include timevar.h. + (lto_materialize_function): Tidy. Add comments. + (lto_wpa_write_files): Tidy. + (lto_execute_ltrans): Tidy. + (lto_main): Add local variable LTO_TIMER. Initialize it + to one of TV_WHOPR_WPA, TV_WHOPR_LTRANS or TV_LTO. + Start and stop the timer. + Tidy comments. + * Make-lang.in (lto.o): Add dependency on timevar.h. + * ltrans-driver: React to -v and -save-temps. + Use simple heuristic to determine how much parallelism to + use when executing make. + +2008-11-12 Doug Kwan + + * lto.c (lto_bitmap_obstack): Remove var. + (lto_materialize_function): Do nothing instead of marking function + body in file if flag_wpa is true. + (lto_add_all_inlinees): Use bitmap functions in lto-utils.c. + (lto_scan_statics_in_cgraph_node): New function. + (lto_promote_cross_file_statics): Same. + (lto_wpa_write_files): Call lto_promote_cross_file_statics. + Use bitmap functions in lto-utils.c. Remove unsued label OUT. + * Make-lang.in (lto/lto.o): Add lto-utils.h to dependency list. + +2008-11-09 Diego Novillo + + * lto/lto.c (lto_fixup_tree): Change error message locus + information to include location of mismatching + declaration. + Use TREE_NO_WARNING to avoid repeated messages. + (lto_main): If lto_fixup_decls emitted any errors, exit. + * lto/lto-lang.c: Don't include libfuncs.h and except.h + (lto_init_options): Don't enable exceptions by default. + (lto_eh_runtime_type): Move to lto-function-in.c + (lto_init_eh): Likewise. + (lto_init): Don't call lto_init_eh. + * lto/Make-lang.in (lto-lang.o): Remove dependency on + libfuncs.h and except.h. + +2008-10-30 Diego Novillo + + * lto.c (lto_read_decls): Declare debug_main only if + LTO_STREAM_DEBUGGING is enabled. + +2008-10-30 Simon Baldwin + + * lto.c (lto_wpa_write_files): Create intermediate files with + make_cwd_temp_file(). + (lto_maybe_unlink): New. Delete intermediate WPA files unless + WPA_SAVE_LTRANS is set. + (lto_main): Call lto_maybe_unlink() for intermediate WPA files. + * ltrans-driver: Do not strip directory from output files. + +2008-10-29 Doug Kwan + + * lto.c (free_decl): Call lto_symtab_clear_resolution when freeing + DECL. + * Make-lang.in (LTO_OBJS): Remove lto/lto-symtab.o + (lto/lto-symtab.o): Remove rule. + * lto-tree.h (struct lang_identifier): Remove LTO specific fields. + (struct lang_decl): Remove RESOLUTION and add DUMMY in struct. + (LANG_IDENTIFIER_CAST, LTO_IDENTIFIER_DECL, LTO_DECL_RESOLUTION): + Remove macros. + lto-symtab.c (File): Move up one level. + lto-lang.c (cgraph.h): Remove include. + (input_overwrite_node, input_node, input_edge, input_cgraph_1, + input_cgraph): Move to lto-cgraph.c in gcc directory above. + (LANG_HOOKS_INPUT_CGRAPH): Remove use of macro. + +2008-10-24 Rafael Espindola + + * lto-function-in.c (get_resolution): Return LDPR_PREEMPTED_IR for + non prevailing weak symbols. + +2008-10-24 Rafael Espindola + + * lto-lang.c (input_cgraph_1): Iterate over nodes, not cgraph_nodes. + +2008-10-24 Rafael Espindola + + * lto-lang.c (input_node): Avoid casts from pointers to ints of + different types. + +2008-10-23 Simon Baldwin + + * lto-lang.c (input_node): Save the node reference, rather than the + node pointer, in node->inlined_to. + (input_cgraph_1): Convert node references into node pointers. + +2008-10-22 Diego Novillo + Rafael Espindola + + * lto.c (lto_resolution_read): Tidy. + * lto-symtab.c (lto_symtab_prevailing_decl): Do not + abort if RET is NULL. + +2008-10-22 Doug Kwan + + * lto.c (lto_fixup_tree): Check for NOTHROW conflict only if + exceptions flag is given. + * lto-lang.c: (lto_init_options) Set default exceptions flag. + (lto_init_eh): Remove exceptions flag initialization. + (lto_init): Only call lto_init_eh if exceptions flag is set. + +2008-10-21 Diego Novillo + + * lto.c: Tidy some formatting. + * lto.h: Likewise. + +2008-10-21 Simon Baldwin + + * lto-symtab.c: (lto_same_type_p): Types cannot be equal if one of + them is NULL (but not the other). + +2008-10-17 Diego Novillo + + * ltrans-driver: Divert output from make to a temporary file. + Show it if the call to make failed. + +2008-10-15 Diego Novillo + + * lto.c (lto_wpa_write_files): Reformat do-while loop. + Do not print TEMP_FILENAME + * ltrans-driver: Call make with -s. + +2008-10-15 Diego Novillo + + * lto-symtab.c (lto_symtab_merge_decl): Do not force + TREE_STATIC on global symbols. + +2008-10-14 Ollie Wild + + * Make-lang.in (LTRANS_DRIVER_INSTALL_NAME): Remove. + (LTRANS_DRIVER_EXE): Add. + (lto.all.cross): Add LTRANS_DRIVER_EXE. + (lto.all.encap): Add LTRANS_DRIVER_EXE. + (lto.install.common): Remove ltrans-driver. + (lto.mostlyclean): Add LTRANS_DRIVER_EXE. + (LTRANS_DRIVER_EXE): New build rule. + * config-lang.in (compilers): Add ltrans-driver. + +2008-10-14 Diego Novillo + + * Make-lang.in (LTRANS_DRIVER_INSTALL_NAME): Disable transformation + of program name. + +2008-10-13 Ollie Wild + + * lang-spec.h (@lto): Replace lto1_options with cc1_options. + * lto.c (lto_execute_ltrans): Add "-fno-wpa -fltrans -xlto" to CFLAGS. + * ltrans-driver (LTRANS_FLAGS): Remove. + +2008-10-08 Doug Kwan + + * lto.c (lto_fixup_tree): Remove ATTRIBUTE_UNUSED from DATA. + Handle new tree codes RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE + and TREE_BINFO. Also move code handling FUNCTION_DECL and VAR_DECL + from lto_fixup_state to here. + (lto_fixup_state): Take an lto_fixup_data_t object DATA instead of + just a free-list. Fix up types also. Move decl merging code to + lto_fixup_tree. + (lto_fixup_state_aux): Change AUX to point to an lto_fixup_data_t + object. + (lto_fixup_decls): Use another pointer set to avoid multiple + walking of nodes except for DECLs to be replaced. Pass an + lto_fixup_data_t object to tree-walker. + +2008-10-08 Rafael Espindola + + * lto-symtab.c (lto_symtab_set_resolution): New. + (lto_symtab_merge_decl): Use lto_symtab_set_resolution and + lto_symtab_get_resolution. + (lto_symtab_prevailing_decl): Return decl for non public decls. + (lto_symtab_get_resolution): New. + * lto.c (lto_fixup_tree, lto_fixup_state): Remove unecessary checks. + +2008-10-06 Rafael Espindola + + * lto-lang.c: Include cgraph.h. + (input_overwrite_node, input_node, input_edge, input_cgraph_1, + input_cgraph): Moved from lto-cgraph.c. + (LANG_HOOKS_INPUT_CGRAPH): New. + +2008-10-03 Rafael Espindola + + * lto.c (lto_fixup_tree, lto_fixup_state): Fix the FIXME. + +2008-10-03 Rafael Espindola + + * lto-symtab.c (lto_symtab_overwrite_decl): Remove. Remove all calls. + (lto_symtab_merge_decl): Update LTO_IDENTIFIER_DECL the reflect the + prevailing definition. Don't mark TREE_NOTHROW differences. + * lto.c (lto_fixup_tree): New. + (lto_fixup_state): New. + (lto_fixup_state_aux): New. + (free_decl): New. + (lto_fixup_decls): New. + (lto_main): Call lto_fixup_decls. + +2008-10-02 Ollie Wild + + * lang.opt (fltrans): Moved from common.opt. Remove RejectNegative + and Init. + (fwpa): Moved from common.opt. Remove RejectNegative and Init. + * lto-lang.c (lto_post_options): Add validation and fixups for + -fltrans and -fwpa. + +2008-10-02 Rafael Espindola + + * lto-symtab.c (lto_symtab_merge_var, lto_symtab_merge_fn, + lto_symtab_merge_decl): Return void. + (lto_symtab_prevailing_decl): New. + +2008-09-30 Rafael Espindola + + * lto-symtab.c (lto_symtab_compatible): Remove the check for already + defined symbols. + (lto_symtab_overwrite_decl): Copy LTO_DECL_RESOLUTION. + (lto_symtab_merge_decl): Store symbol resolution in LTO_DECL_RESOLUTION. + Check for already defined symbols. + * lto-tree.h (lang_decl): Remove dummy and add resolution fields. + (LTO_IDENTIFIER_RESOLUTION): Remove. + (LTO_DECL_RESOLUTION): New. + +2008-09-30 Rafael Espindola + + * lto.c (lto_read_decls): Use new input_tree signature. + +2008-09-26 Doug Kwan + + * lto.c (lto_main): Call lto_fixup_nothrow_decls to fix up function + bodies affected by exception attribute merging of DECLs. + * lto-symtab.c (lto_symtab_merge_decl): Handle exception attribute + merging. + +2008-09-25 Rafael Espindola + + * Make-lang.in (PLUGIN_API_H, LTO_TREE_H): New. + (lto/lto-lang.o, lto/lto.o, lto/lto-symtab.o) Use LTO_TREE_H. + * lto-symtab.c (lto_symtab_compatible): New. + (lto_symtab_overwrite_decl): New. + (lto_symtab_merge_decl): Refactor to use the above functions + and the resolution from lang_identifier. + * lto-tree.h: Include plugin-api.h. + (lang_identifier): Add resolution. + (LTO_IDENTIFIER_RESOLUTION): New. + +2008-09-25 Ollie Wild + + * lang.opt (fltrans-output-list=): New option. + * lto.c (lto_execute_ltrans): Output file names to ltrans_output_list. + +2008-09-25 Rafael Espindola + + * lto.c (lto_resolution_read): Initialize ret; + +2008-09-24 Ollie Wild + + * lto.c (sys/mman.h): Move include. + (lto_wpa_write_files): Return a list of written files. + (lto_execute_ltrans): New function. + (lto_main): Call lto_execute_ltrans. + (ltrans-driver): New file. + * lto-lang.c (DEFAULT_LTRANS_DRIVER): New macro. + (DEAULT_LTRANS_DRIVER_LEN): New macro. + (lto_init_options): Initialize ltrans_driver. + (lto_handle_option): Fix incorrect default output value. + * lang.opt (fltrans-driver=): New option. + * Make-lang.in (LTRANS_DRIVER_INSTALL_NAME): New variable. + (lto.install-common): Add lto/ltrans-driver. + +2008-09-24 Rafael Espindola + + * Make-lang.in (LTO_OBJS): Add lto/common.o. + (lto/lto.o): Depend on lto/common.h. + (lto/common.o): New. + * lang.opt (resolution): New. + * lto-lang.c (resolution_file_name): New. + (lto_handle_option): Handle OPT_resolution. + * lto-symtab.c (lto_symtab_merge_decl): Add a resolution argument. + (lto_symtab_merge_var,lto_symtab_merge_fn): Add a resolution argument. + pass it to lto_symtab_merge_decl. + * lto.c: Include common.h. + (lto_read_decls): Add resolutions and resolutions_size arguments. + Initialize data_in.globals_resolution and + data_in.globals_resolution_size. + (index_and_symbol_resolution): New. + (lto_resolution_read): New. + (lto_file_read): Add argument resolution_file. + Read resolution. + * lto.h (resolution_file_name): New. + +2008-09-23 Rafael Espindola + + * common.c: Update description. + * common.h: Update description. + +2008-09-23 Rafael Espindola + + * common.c: Moved from lto-plugin. + * common.h: Moved from lto-plugin. + +2008-09-22 Doug Kwan + + * lto.c (VEC(bitmap,heap)): Declare. + (lto_materialize_function): Handle WAP mode specially. + (lto_add_inline_clones): New. + (lto_add_all_inlinees): Changle algorithm and to use bitmaps. Also + return a bitmap of inlined decls. + (lto_wpa_write_files): Handle all DECLs brought in by inlining. + (lto_main): Call reset_inline_failed to reset inlining states. + Check call-graph after WPA inlining. + * lto-lang.c (lto_init): Do not clear flag_generate_lto + unconditionally. + +2008-09-19 Doug Kwan + + lto.c (lto_main): Remove unsued wrapper code. + lang-specs.h (@lto): Use lto1_options instead of cc1_options. + +2008-09-19 Rafael Espindola + + * lto-symtab.c: Include lto-tree-in.h. + * lto-tree.h (lto_symtab_merge_var, lto_symtab_merge_fn): Remove. + * lto.h (lto_symtab_merge_var, lto_symtab_merge_fn): Remove + * Make-lang.in (lto/lto-symtab.o): Add lto-tree-in.h. + +2008-09-17 Paolo Bonzini + Rafael Avila de Espindola + + * lto-lang.c (COMPOUND_LITERAL_EXPR_DECL_STMT, + COMPOUND_LITERAL_EXPR_DECL): Remove. + (emit_local_var): Remove. + (lto_expand_expr): Remove. + (lto_staticp): Remove. + (LANG_HOOKS_EXPAND_EXPR): Remove. + (LANG_HOOKS_STATICP): Remove. + +2008-09-11 Diego Novillo + + * lto-lang.c: Include except.h and libfuncs.h. + (lto_init_eh): New. + (lto_init): Call it. + Set flag_generate_lto to 0. + * Make-lang.in (lto-lang.o): Add dependency on except.h + and libfuncs.h. + +2008-09-09 Bill Maddox + + * lto-lang.c: Include header file expr.h. + (COMPOUND_LITERAL_EXPR_DECL_STMT, + COMPOUND_LITERAL_EXPR_DECL): Copied from c-common.h. + (emit_local_var): Copied from c-semantics.c. + (lto_expand_expr, lto_staticp): Copied from c_expand_expr + and c_staticp in c-common.c. + (LANG_HOOKS_EXPAND_EXPR,LANG_HOOKS_STATICP): Redefined. + +2008-09-08 Diego Novillo + + * lto-lang.c (lto_global_bindings_p): Return 1 during + IPA passes. + +2008-09-07 Diego Novillo + + * lto.c: Tidy formatting. + +2008-08-04 Bill Maddox + + * lto-symtab.c (lto_symtab_merge_decl): Add comment. + +2008-09-03 Doug Kwan + + lto.c (lto_add_all_inlinees): Reset FAILED_REASON of edges to + CIF_OK instead of NULL. + +2008-09-02 Diego Novillo + Simon Baldwin + + * lto-lang.c (lto_type_for_size): Rewrite. Adapt from + c_common_type_for_size. + (lto_type_for_mode): Remove ATTRIBUTE_UNUSED markers. + (lto_init): Call linemap_add. + (signed_and_unsigned_types): Remove. + +2008-08-29 Diego Novillo + + * lto-lang.c (handle_noreturn_attribute): New local function. + (handle_const_attribute): New local function. + (handle_malloc_attribute): New local function. + (handle_pure_attribute): New local function. + (handle_novops_attribute): New local function. + (handle_nonnull_attribute): New local function. + (handle_nothrow_attribute): New local function. + (handle_sentinel_attribute): New local function. + (handle_type_generic_attribute): New local function. + (handle_format_attribute): New local function. + (handle_format_arg_attribute): New local function. + (lto_attribute_table): Declare. + (lto_format_attribute_table): Declare. + (lto_init_attributes): New local function. + (lto_define_builtins): Call it. + Call targetm.init_builtins and build_common_builtin_nodes. + (LANG_HOOKS_COMMON_ATTRIBUTE_TABLE): Define. + (LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE): Define. + +2008-08-28 Diego Novillo + + * Make-lang.in (lto-lang.o): Replace tree-gimple.h with + $(GIMPLE_H). + (lto-symtab.o): Add dependency on $(GIMPLE_H). + * lto-lang.c: Include gimple.h instead of tree-gimple.h. + * lto-symtab.c: Include gimple.h. + * lto-tree.h (chain_next): Replace GENERIC_NEXT with + TREE_CHAIN. + +2008-08-27 Doug Kwan + + * lto.c (vec.h, bitmap.h, pointer-set.h, ipa-prop.h, ggc.h, + gt-lto-lto.h): New includes. + (lto_materialize_function): Do not read in function body in WPA mode. + Format a line to fit in 80 columns. + (lto_cgraph_node_sets): New garbage collected variable. + (lto_1_to_1_map, lto_add_all_inlinees, lto_wpa_write_files): + New functions. + (lto_main): Initialize bitmap obstack. Add code to handle WPA mode. + * Make-lang.in (LTO_H): Replace filename lto-section-in.h with + variable LTO_SECTION_IN_H. + (lto/lto.o): Include gt-lto-lto-c.h ggc.h ,VEC_H, BITMAP_H, + pointer-set.h and IPA_PROP_H. Also replace filename lto-section-in.h + with variable LTO_SECTION_IN_H. + * config-lang.in (gtfiles): Add lto/lto.c. + * lto-symtab.c (lto_symtab_merge_decl): Set DECL_CONTEXT of + merged DECL_RESULT correctly. + +2008-08-26 Bill Maddox + + * lto-lang.c Include tree-gimple.h. + (lto_mark_addressable): Call mark_addressable rather than + asserting. + (lto_post_options): Suppress debug info generation. + * Make-lang.in: Add dependency of lto-lang.o on tree-gimple.h. + +2008-08-25 Bill Maddox + + * lto-symtab.c (lto_symtab_merge_decl): Remove a suspect + assertion and leave an explanatory comment in its place. + +2008-08-21 Doug Kwan + + * lto.c (preload_common_nodes): Call lto_get_common_nodes to get a list + of common nodes instead of computing locallly. + (lto_read_in_decl_state): New. + (lto_read_decls): Change code for udpate in struct lto_decl_header. + Read global and per-function in-decl states. + * Make-lang.in (LTO_H): Update dependency. + (lto/lto.o): Same. + (lto-symtab.c): Merge (revision 139039) + * lto-symtab.c (lto_symtab_merge_decl): Merge DECL_RESULT. + +2008-08-21 Rafael Espindola + + * config-lang.in (target_libs): New. + +2008-08-20 Bill Maddox + + * lto.c (current_lto_file): Remove GTY marker from static + variable. Remove include of file gt-lto-lto.h. + * Make-lang.in: Remove dependency of lto/lto.o on + gt-lto-lto.h. + * lto-elf.c (lto_file_close): Removed. + (lto_elf_file_open): Use XCNEW instead of GGC_CNEW to + allocate lto_elf_file object. + (lto_elf_file_close): Free lto_elf_file object after close. + * lto.h (struct lto_file_struct): Remove GTY marker. + * config-lang.in: Remove lto/lto.h and lto/lto.c from + gtfiles. + +2008-08-20 Bill Maddox + + * lto.c (lto_read_decls): Provide dummy argument to input_tree + to conform to its new signature. + * lto-symtab.c (lto_symtab_merge_decl): Do not invoke ggc_free + on discarded node here, now called in global_vector_fixup. + +2008-08-09 Bill Maddox + + * lto.c (preload_common_nodes): Verify that fileptr_type_node + has not been set to a front-end-specific value. + +2008-08-05 Doug Kwan + + * Make-lang.in (lto-symtab.o): Add missing dependencies to fix + build breakage. + +2008-07-30 Bill Maddox + + * lto.c (lto_materialize_function): Call lto_original_decl_name. + Remove obsolete comments. + (lto_read_decls): Remove initialization of deleted field data_in.global. + Tidy up comments. + (lto_main): Remove redundant initialization of section_hash_table. + * lto-elf.c: Removed obsolete comments. + * lto.h: Tidy up comments. + * lto-symtab.c (lto_least_common_multiple): New function. + (lto_symtab_merge_decl): Merge variable alignments in some cases. + Tidy up comments. + +2008-07-25 Diego Novillo + Bill Maddox + + * lto.c: Re-order include files. + Include lto-section-out.h. + (preload_common_nodes): Add debugging output. + Add new local INDEX_TABLE. + Call preload_common_node. + * Make-lang.in (lto.o): Add dependency on lto-section-out.h + +2008-07-13 Bill Maddox + + * lto.c (lto_read_decls): Cast pointer to const char * to avoid + unwanted scaling during pointer addition. + +2008-07-11 Bill Maddox + Diego Novillo + + * lto.c (lto_read_decls): Fix C++ compatibility warnings. + Make code const-correct. + (lto_file_read): Fix C++ compatibility warnings. + (lto_read_section_data): Fix C++ compatibility warnings. + (lto_get_section_data): Use CONST_CAST to avoid warning when + const pointer passed to free. + * lto-elf.c (lto_elf_build_section_table): Fix C++ + compatibility warnings. + (lto_elf_append_data): Fix C++ compatibility warnings. Use CONST_CAST + to avoid warning assigning const pointer to d_buf field of Elf_Data. + (lto_get_current_out_file): Fix C++ compatibility warnings. + +2008-07-11 Diego Novillo + + * Make-lang.in (lto-warn): Define. + +2008-07-03 Simon Baldwin + + * lto.c (lto_read_decls): Wrapped debug-only data items within #ifdef + LTO_STREAM_DEBUGGING. + +2008-06-27 Ollie Wild + + * lto-elf.c (lto-section-out.h): New include. + (struct lto_elf_file): Remove bits member. Add scn, shstrtab_stream, + and data members. + (cached_file_attrs): New static variable. + (lto_elf_get_shdr, lto_elf_free_shdr): Remove elf_file parameter. + Use cached_file_attrs for checking bits. + (lto_elf_build_section_table): Remove elf_file argument from + lto_elf_get_shdr and lto_elf_free_shdr calls. + (DEFINE_INIT_SHDR): New macro. + (init_shdr32, init_shdr64): New functions defined via the + DEFINE_INIT_SHDR macro. + (lto_elf_begin_section_with_type): New function. + (lto_elf_begin_section): New function. + (lto_elf_append_data): New function. + (lto_elf_end_section): New function. + (DEFINE_VALIDATE_EHDR): New macro. + (validate_ehdr32, validate_ehdr64): New functions defined via the + DEFINE_VALIDATE_EHDR macro. + (validate_file): New function. + (DEFINE_INIT_EHDR): New macro. + (init_ehdr32, init_ehdr64): New functions defined via the + DEFINE_INIT_EHDR macro. + (init_ehdr): New function. + (lto_elf_file_open): Add support for writable files. Move some + validation logic to validate_file. + (lto_elf_file_close): Add support for writable files. Write file data + and free data blocks. + (current_out_file): New static variable. + (lto_set_current_out_file): New function. + (lto_get_current_out_file): New function. + * lto.c (lto_main): Add writable argument to lto_elf_file_open calls. + Add temporary initialization for testing ELF serialization. + * lto.h (lto-section-out.h): New include. + (struct lto_file_struct): Slight modification to comment. + (lto_elf_file_open): Add writable parameter. + (lto_elf_begin_section): New function declaration. + (lto_elf_append_data): New function declaration. + (lto_elf_end_section): New function declaration. + (lto_set_current_out_file, lto_get_current_out_file): New function + declarations. + * lto-lang.c (LANG_HOOKS_BEGIN_SECTION): Set as lto_elf_begin_section. + (LANG_HOOKS_APPEND_DATA): Set as lto_elf_append_data. + (LANG_HOOKS_END_SECTION): Set as lto_elf_end_section. + * Make-lang.in (LTO_H): Add lto-section-out.h. + +2008-06-12 Ollie Wild + + * lto.h (struct lto_file_vtable_struct): Remove. + (struct lto_file_struct): Remove vtable member. + * lto-elf.c (lto_file_init): Remove vtable argument. + (lto_elf_map_optional_lto_section): Remove. + (lto_elf_unmap_section): Remove. + (lto_elf_file_vtable): Remove. + (lto_elf_file_open): Remove lto_elf_file_vtable argument from + lto_file_init call. + (lto_elf_find_section_data): Remove. + +2008-06-11 Ollie Wild + + * lto.c (lto_file_read): Add const qualifier to data variable. + +2008-06-11 Diego Novillo + + Merge from lto-streamber sub-branch. + + 2008-06-04 Ollie Wild + + * lto.c: Remove inclusion of dwarf2.h and dwarf2out.h. + * Make-lang.in (lto.o): Remove dependency on dwarf2.h. + + 2008-05-28 Bill Maddox + + Replace the DWARF reader in the LTO front-end. + + * lto.c: Include lto-tree-in.h, lto-tags.h. + (enum DWARF2_class, DW_cl_constant, struct + DWARF2_form_data, struct lto_context, + lto_fd_init, lto_info_fd_init, + lto_abbrev_fd_init, lto_info_fd_close, + lto_file_init, lto_file_close, + lto_file_corrupt_error, lto_abi_mismatch_error, + LTO_CHECK_INT_VAL, LTO_READ_TYPE, + lto_read_uleb128, lto_read_sleb128, + lto_read_initial_length, lto_abbrev_read_attrs, + lto_abbrev_read, lto_abbrev_read_lookup, + lto_read_section_offset, + lto_read_comp_unit_header, find_cu_for_offset, + lto_get_file_name, + lto_resolve_reference,lto_read_form, + attribute_value_as_int, + make_signed_host_wide_int, + attribute_value_as_constant, lto_cache_hash, + lto_cache_eq, lto_cache_store_DIE, + lto_cache_lookup_DIE, lto_find_integral_type, + lto_find_integral_type_1, + LTO_BEGIN_READ_ATTRS_UNCHECKED, + LTO_BEGIN_READ_ATTRS, LTO_END_READ_ATTRS, + lto_unsupported_attr_error, lto_get_identifier, + lto_read_referenced_type_DIE, + lto_read_compile_unit_DIE, + lto_read_array_type_DIE, + lto_read_structure_union_class_type_DIE, + lto_read_enumerator_DIE, + lto_read_enumeration_type_DIE, + lto_read_only_for_child_DIEs, + lto_read_only_for_child_DIEs, + lto_read_member_DIE, lto_read_abbrev, + lto_read_variable_formal_parameter_constant_DIE, + lto_get_body): Removed. + (preload_common_nodes): New function. + (lto_read_decls): Convert for new global streamer. + (lto_materialze_file_data, + lto_read_subroutine_type_subprogram_die, + lto_read_unspecified_parameters_DIE, + lto_read_typedef_DIE, + lto_read_pointer_reference_type_DIE, + lto_read_subrange_type_DIE, + lto_read_base_type_DIE, + lto_read_const_volatile_restrict_type_DIE, + lto_read_namespace_DIE, + lto_read_unspecified_type_DIE, lto_read_DIE, + lto_read_child_DIEs, lto_collect_child_DIEs): + Removed. + (lto_info_read, lto_set_cu_context): Removed. + (lto_file_read): Convert for new global streamer. + (lto_resolve_type_ref, lto_read_DIE_at_ptr, + lto_resolve_var_ref, lto_resolve_fn_ref, + lto_resolve_field_ref, lto_resolve_typedecl_ref, + lto_resolve_namespacedecl_ref): Removed. + (lto_file_init, lto_file_close): Moved to lto-elf.c. + * lto-tree.h (lto_symtab_merge_var, + lto_symtab_mergee_fun): Declare here. + * lto-elf.c (lto_file_init, lto_file_close): Moved from lto.c. + (lto_elf_file_open): Removed code to read DWARF debug sections. + * lto.h (lto_context, DWARF2_attr, DWARF2_abbrev, + DWARF2_CompUnit, lto_die_ptr, + lto_die_cache_entry, lto_fd, lto_info_fd, + lto_abbrev_fd): Removed. + (lto_file): Removed debug_info and debug_abbrev fields. + (lto_ref): Removed. + (lto_file_init, lto_file_close, + lto_resolve_type_ref, lto_resolve_var_ref, + lto_resolve_fn_ref, lto_resolve_field_ref, + lto_resolve_typedecl_ref, + lto_resolve_namespacedecl_ref, + lto_get_file_name): Removed declarations. + (lto_symtab_merge_var, lto_symtab_merge_fn): + Declarations moved to lto-tree.h. + * lto-symtab.c (lto_compatible_attributes_p): + Lobotomize this, as it barfs on "Hello, world!". + * lto-section-out.c: Include lto-tree-out.h. + (lto_hash_global_slot_node, + lto_eq_global_slot_node, preload_common_nodes, + write_global_stream, write_global_references): + New functions. + (produce_asm_for_decls): Convert for new global streamer. + * lto-section-out.h (lto_hash_global_slot_node, + lto_eq_global_slot_node): Declare. + +2008-06-07 Kenneth Zadeck + Jan Hubicka + + * lto.c (sys/mman.h, tree-pass.h): New includes. + (lto_materialize_constructors_and_inits, + lto_materialize_function): Keeps length of section. + (lto_materialize_cgraph): Removed. + (lto_read_decls): Initialize fd field. + (lto_file_read): Different return type and removed much code to + lto_main. + (page_mask): New variable. + (lto_read_section_data, get_section_data, free_section_data): New + functions. + (lto_main): Now calls pass manager, sets the hooks so that the ipa + passes can get the section data. + +2008-05-27 Kenneth Zadeck + + * lto.h (lto_read_decls): Made local. + (lto_input_function_body, lto_input_constructors_and_inits, + lto_input_cgraph): Declarations moved to lto-section-in.h. + * lto-section-in.c: Moved to .. . + * lto-cgraph-in.c: Ditto. + * lto-section-in.h: Ditto. + * lto-function-in.c: Ditto. + * lto-lang.c (lto_handle_option): Added ATTRIBUTE_UNUSED to parms. + (lto_insert_block): Removed. + (LANG_HOOKS_INSERT_BLOCK): Removed. + * Make-lang.in (lto-cgraph-in.o, lto-function-in.o, + lto-section-in.o): Rules moved to lto/Makefile.in. + + +2008-05-16 Ollie Wild + + * lto-lang.c (tree-inline.h): Include. + (lto_post_options): New function. + (LANG_HOOKS_POST_OPTIONS): Define. + * lto-cgraph-in.c (overwrite_node): Set node->global.insns. + * lto-function-in.c (input_bb): Set TREE_BLOCK (stmt). + +2008-05-13 Diego Novillo + + * lto-function-in.c (input_ssa_names): Call + make_ssa_name_fn instead of make_ssa_name. + +2008-05-12 Diego Novillo + + * lto-cgraph-in.c (overwrite_node): Update references to + inline summary fields. + * lto-function-in.c (input_expr_operand): Do not handle + STRUCT_FIELD_TAG. + +2008-05-09 Ollie Wild + + * lang.opt: New file. + * lto-lang.c (lto_init_options): New function. + (lto_handle_option): New function. + (lto_init): Move initialization of flag_unit_at_a_time to + lto_init_options. + (LANG_HOOKS_INIT_OPTIONS): Define. + (LANG_HOOKS_HANDLE_OPTION): Define. + +2008-04-29 Ollie Wild + + * lto.c (lto_read_namespace_DIE): New function. + (lto_read_DIE): Add lto_read_namespace_DIE callback. Cache + NAMESPACE_DECL DIE's. + (lto_resolve_namespacedecl_ref): New function. + * lto.h (lto_resolve_namespacedecl_ref): New function. + * lto-section-in.c (lto_read_decls): Read namespace declarations. + * lto-section-in.h (struct lto_file_decl_data): Add namespace_decls + and num_namespace_decls. + * lto-function-in.c (input_expr_operand): Add NAMESPACE_DECL case. + * lto-lang.c (lto_init_ts): New function. + (LANG_HOOKS_INIT_TS): Set as lto_init_ts. + +2008-04-16 Ollie Wild + + * lto-function-in.c (input_type_ref): Updated function description. + +2008-04-16 Ollie Wild + + * lto-function-in.c (input_type_ref_1): New function. + (input_type_ref): Split into two functions. + (input_function): Add support for type contexts. + +2008-04-16 Ollie Wild + + * lto.c (lto_materialize_function): Use DECL_ASSEMBLER_NAME to compute + section name + +2008-04-16 Ollie Wild + + * lto.c (lto_read_compile_unit_DIE): Add DW_LANG_C_plus_plus to the + list of supported languages. + +2008-03-25 Kenneth Zadeck + + Merge with mainline @133491. + +2008-03-05 Kenneth Zadeck + Jan Hubicka + + * lto.c (lto_info_fd_init, lto_info_fd_close): Get rid of + fd->unmaterialized_fndecls. + (lto_get_file_name, lto_materialize_cgraph): New function. + (lto_materialize_constructors_and_inits, + lto_materialize_function): Read info directly from elf file. + (lto_file_read): Made local and initialize dictionary so that + other lto sections can be read without reprocessing the elf file. + (lto_main): Read all functions after all files have been processed + for their types, globals and cgraph. + * Make-lang.in (lto.o, lto-cgraph-in.c, lto-section-in): Changed + dependencies. + * lto-elf.c (lto_elf_file): Removed strtab, symtab fields. + (hash_name, eq_name, lto_elf_build_section_table): New functions. + (lto_elf_read_symtab): Removed function. + (lto_elf_file_open): Removed call to lto_elf_read_symtab. + * lto.h (lto_info_fd_struct): Removed unmaterialized_fndecls. + (lto_file_read): Made local. + (lto_get_file_name, lto_elf_build_section_table, + lto_input_cgraph): + New function. + * lto-section-in.c (lto_read_section_data, lto_get_section_data): + New functions. + (lto_read_decls): Get the file name. + * lto-cgraph-in.c: New file. + * lto-function-in.c (tag_to_expr): Stops at LTO_tree_last_tag. + (input_expr_operand, lto_read_body): Set lto_debug_context.tag_names. + (input_labels): Fixed latent sizeof issue. + (input_function): Build stmt array to set call sites into cgraph + edges. + (lto_read_body): Reset cfun->curr_properties. + * lto_section_in.h (lto_section_slot): New structure. + (section_hash_table.lto_file_decl_data): New field. + + +2008-02-09 Kenneth Zadeck + + * lto.c (lto_read_variable_formal_parameter_const): Remove code to + reconstruct static initializers. + (lto_get_body, lto_materialize_function): Add lto_section_type as + a parameter. + (lto_materialize_constructors_and_inits, + lto_materialize_file_data): New function. + (lto_materialize_function, + lto_read_subroutine_type_subprogram_DIE): Renamed unmap_fn_body to + unmap_section and map_fn_body to map_section. + (lto_set_cu_context): Process functions and static inits + differently. + * Make-lang.in (LTO_H, lto/lto-function-in.o, + lto/lto-section-in.o): Update dependencies. + * lto/lto-elf.c (lto_elf_map_optional_lto_section): Add + lto_section_type parameter. + (lto_elf_unmap_fn_body): Renamed to lto_elf_unmap_section. + * lto.h (lto_file_vtable_struct): Removed two of the fields and + renamed the other two so that there is only one map function and + one unmap function and each takes a section type parameter. + (lto_read_function_body): Renamed to lto_input_function_body and + added file_data parameter. + (lto_read_var_init): Removed. + (lto_input_constructors_and_inits): New function. + * lto-section-in.c (lto_read_decls): New function. + * lto-function-in.c (data_in): Moved fields field_decls, fn_decls, + var_decls, type_decls, types to lto_file_decl_data. + (input_type_ref, input_expr_operand, lto_read_body): Get + field_decls, fn_decls, var_decls, type_decls, types from different + structure. + (input_globals, input_constructor, lto_read_var_init): Removed. + (input_constructors_or_inits): New function. + (lto_read_function_body, lto_input_constructors_and_inits): + Renamed to lto_input_function_body and takes file_data parameter. + * lto-section-in.h (lto_file_decl_data): New structure. + +2008-01-28 Kenneth Zadeck + + * lto-function-in.c (input_globals.c): Changed input type to + lto_function_header. + (input_bb): Removed code to deserialize the stmt number. + (input_function): Renumber all stmts after they are input. + (lto_read_body, lto_read_function_body, lto_read_var_init): + Changed to used new header format and enum section_type. + *lto-lang.c (success): Removed. + +2008-01-28 Nathan Froyd + + * lto-elf.c (lto_elf_lookup_sym): Remove unused function. + (lto_elf_free_sym): Likewise. + + * lto-elf.c (lto_elf_read_var_init): Remove unused function. + (lto_elf_build_init): Likewise. + +2008-01-14 Kenneth Zadeck + + * lto-read.c: Renamed to lto-function-in.c. + (input_1_unsigned): Moved to lto-section-in.c and renamed + lto_input_1_unsigned. + (input_uleb128): Moved to lto-section-in.c and renamed + lto_input_uleb128. + (input_widest_uint_uleb128): Moved to lto-section-in.c and renamed + lto_input_widest_uint_uleb128. + (input_sleb128): Moved to lto-section-in.c and renamed + lto_input_sleb128. + (input_integer): Moved to lto-section-in.c and renamed + lto_input_integer. + (debug_in_fun): Moved to lto-section-in.c and renamed + lto_debug_in_fun. + (input_block): Moved to lto-section-in.h and renamed + lto_input_block. + (input_expr_operand): Fixed to allow lists with more than one + element. + * lto-section-in.h: New file. + * lto-section-in.c: New file with changes from above. + * Make-lang.in (lto-read.o): Renamed lto-function-in.c. + (lto-section-in.o): New rule. + +2007-12-29 Nathan Froyd + + * lto-read.c (input_expr_operand): Mark static and external + VAR_DECLs as needed. + +2007-12-29 Nathan Froyd + + * lto-read.c (input_integer): Use the correct shift amount. + +2007-12-29 Nathan Froyd + + * lto-lang.c (lto_pushdecl): Do nothing instead of aborting. + (LANG_HOOKS_NAME): Define. + +2007-12-27 Nathan Froyd + + * lto.c (lto_find_integral_type): Define as a macro. Rename the + original function to... + (lto_find_integral_type_1): ...this. Consult UNSIGNEDP if we + don't have a base type. + (lto_read_enumeration_type_DIE): Examine the values of the + enumeration to determine whether we can use an unsigned type for + the base type of the enumeration. + +2007-12-24 Nathan Froyd + + * lto.c (lto_read_structure_union_class_type_DIE): Set TYPE_MODE + and TYPE_ALIGN on UNION_TYPEs as soon as possible. + +2007-12-22 Nathan Froyd + + * lto-lang.c (lto_types_compatible_p): New function. + (LANG_HOOKS_TYPES_COMPATIBLE_P): Define. + +2007-12-22 Nathan Froyd + Kenneth Zadeck + + * lto-read.c (input_expr_operand): Fixed uninitialize var warning. + (input_local_vars): Read in DECL_INITIAL and context for local + statics that need to be put in unexpanded_vars_list. + +2007-12-21 Nathan Froyd + + * lto-read.c (input_real): Use a separate null-terminated buffer + for calling real_from_string. + (input_expr_operand): If we take the address of a FUNCTION_DECL, + tell cgraph that it's needed. + +2007-12-19 Doug Kwan + + * lto.c (lto_read_base_type_DIE): Handle complex integer types. + +2007-12-18 Nathan Froyd + + * lto.c (lto_read_DIE): Call lto_read_only_for_child_DIEs instead. + (lto_file_read): Reset the members of 'context' every time we read + a toplevel DIE, with special attention to last_param_type. + +2007-12-18 Nathan Froyd + + * lto.c (lto_read_subroutine_type_subprogram_DIE): Initialize + 'declaration'. Set the assembler name for non-public functions. + +2007-12-17 Kenneth Zadeck + + * lto_read.c (data_in.unexpanded_indexes): New array. + (input_local_var): Added code to read in unexpanded_var_list + indexes for variables. Only read in DECL_CHAIN field for + parameters. + (input_local_vars): Added code to rebuild unexpanded_var_list in + order using unexpanded_indexes. + (input_function): Added code to set DECL_CONTEXT for functions. + +2007-12-13 Doug Kwan + + * lto.c (lto_read_pointer_reference_type_DIE): Handle optional name + in pointer and reference types. + +2007-12-13 Nathan Froyd + + * lto-read.c (input_expr_operand): Use DECL_RESULT when reading a + RESULT_DECL. + +2007-12-13 Nathan Froyd + + * lto.c (lto_read_array_type_DIE): Return the cached DIE if we've + already read the DIE. + (lto_get_body): New function, split out from... + (lto_materialize_function): ...here. Call it. + (lto_read_subroutine_type_subprogram_DIE): Call lto_get_body to + determine DECL_EXTERNAL. + * lto-symtab.c (lto_symtab_merge_decl): Merge the DECL_RESULTs of + FUNCTION_DECLs when necessary. Use the type of the actual + function definition if we are unable to easily merge types. Ignore + spurious DECL_MODE mismatches on VAR_DECLs. Merge DECL_MODEs when + necessary. + +2007-12-13 Nathan Froyd + + * lto-lang.c (LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS): Define. + +2007-12-12 Bill Maddox + + Revert + 2007-12-07 Bill Maddox + + * lto.c (lto_str_fd_init): New function. + (lto_str_fd_close): New function. + (lto_file_init): Call lto_str_fd_init. + (lto_file_close): Call lto_str_fd_close. + (lto_str_read): New function. Read debug string table. + (lto_str_lookup): New function. Get string for debug + string table offset. + (lto_read_form): Recognize DW_FORM_strp. + (lto_file_read): Invoke lto_str_read. + + * lto-elf.c (lto_elf_file_open): Read raw section data + for the .debug_str section, if present. + + * lto.h (struct lto_str_fd_struct): New struct. + (struct lto_file_struct): Added new field DEBUG_STR + to hold the file descriptor for the debug string table. + +2007-12-07 Bill Maddox + + * lto.c (lto_str_fd_init): New function. + (lto_str_fd_close): New function. + (lto_file_init): Call lto_str_fd_init. + (lto_file_close): Call lto_str_fd_close. + (lto_str_read): New function. Read debug string table. + (lto_str_lookup): New function. Get string for debug + string table offset. + (lto_read_form): Recognize DW_FORM_strp. + (lto_file_read): Invoke lto_str_read. + + * lto-elf.c (lto_elf_file_open): Read raw section data + for the .debug_str section, if present. + + * lto.h (struct lto_str_fd_struct): New struct. + (struct lto_file_struct): Added new field DEBUG_STR + to hold the file descriptor for the debug string table. + +2007-12-07 Nathan Froyd + + * lto-read.c (input_cfg): Call init_empty_tree_cfg_for_function. + Grow the basic_block_info and label_to_block_map vectors if + necessary. Read in the block chain. + +2007-12-06 Nathan Froyd + + * lto.c (lto_read_DIE): Set TYPE_ALIAS_SET where necessary. + +2007-12-06 Nathan Froyd + + * lto.c (lto_read_form): Add DW_cl_address for DW_AT_const_value. + +2007-12-06 Nathan Froyd + + * lto-read.c (input_expr_operand): Don't check for MTAGs. + (lto_read_body): Don't declare PROP_alias. + +2007-12-06 Nathan Froyd + + * lto-symtab.c (lto_symtab_merge_decl): Handle FUNCTION_DECLs without + argument type information. + +2007-12-03 Nathan Froyd + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Set + TREE_THIS_VOLATILE if the associated type is a volatile type. + (lto_materialize_function): Remove call to init_ssa_operands. + * lto-read.c (input_expr_operand): Add SSA_NAME_VAR as a referenced + variable when reading an SSA_NAME. Do the same when reading a + RESULT_DECL, a RETURN_EXPR, or an MTAG. + (input_cfg): Call init_ssa_operands. + (input_ssa_names): Set the default def of an SSA_NAME if necessary. + Move call to init_tree_ssa... + (lto_read_body): ...here. Use push_cfun and pop_cfun. Call + add_referenced_var on any variables referenced from the body of the + function. Inform the rest of the compiler we are in SSA form and + inform later passes about the current properties. + +2007-11-30 Nathan Froyd + + * lto.c (lto_materialize_function): Add FIXME. + +2007-11-29 Nathan Froyd + + * lto-lang.c (enum built_in_attribute): New enum. + (flag_no_builtin, flag_no_nonansi_builtin, flag_isoc94, flag_isoc99, + built_in_attributes): New variables. + (def_builtin_1): New function. + (lto_define_builtins): #define DEF_BUILTIN and include builtins.def. + +2007-11-28 Nathan Froyd + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Set + DECL_SOURCE_LOCATION for debugging purposes. + (lto_read_member_DIE): Set DECL_SOURCE_LOCATION. If we have read a + bitfield, use the type specified by the DIE for TREE_TYPE and defer + laying out the decl until later. + (lto_read_subroutine_type_subprogram_DIE): Compare the function's + name with DECL_ASSEMBLER_NAME. Set DECL_SOURCE_LOCATION and + TREE_ADDRESSABLE. + * lto-read.c (input_expr_operand): Set TREE_ADDRESSABLE on the + operand of an ADDR_EXPR. + * lto-lang.c (enum lto_builtin_type): New enum. + (builtin_type): New typedef. + (builtin_types, string_type_node, const_string_type_node, + wint_type_node, intmax_type_node, uintmax_type_node, + signed_size_type_node): New variables. + (def_fn_type, builtin_type_for_size, lto_define_builtins, + lto_build_c_type_nodes): New functions. + (lto_init): Initialize builtin types. + (lto_set_decl_assembler_name): Let the target machine mangle the + name if the decl is TREE_PUBLIC, otherwise uniquify it. + +2007-11-21 Nathan Froyd + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Don't + set TREE_ADDRESSABLE. Do set DECL_COMDAT. Set TREE_READONLY if + the type is a constant type. Set the assembler name and inform + the rest of the compiler about the new decl if the decl is not + public. + (lto_read_subroutine_type_subprogram_DIE): Don't check for equivalency + of DECL_ASSEMBLER_NAME when determining if we have a builtin. Don't + try to read in function bodies for functions that already have bodies. + * lto-symtab.c (lto_same_type_p): Check for unbounded array + equivalency. + (lto_symtab_merge_decl): Don't merge decls that aren't TREE_PUBLIC. + Check for whether we matched a builtin function type before calling + lto_same_type_p on the generated type. Permit cases where the + declaration of an array is unbounded, but the definition is bounded. + Don't combine TREE_PUBLIC flags. Copy over DECL_SIZE and + DECL_SIZE_UNIT if necessary. + +2007-11-16 Kenneth Zadeck + + * lto-read.c (input_expr_operand): Get types right + for COMPLEX_CST. + +2007-11-16 Kenneth Zadeck + + * lto-read.c (make_new_block, input_cfg): Properly set + n_basic_blocks. + +2007-11-16 Nathan Froyd + + * lto.c (lto_read_array_type_DIE): Handle DIEs with DW_AT_GNU_vector + set properly by building a VECTOR_TYPE instead of an ARRAY_TYPE. + +2007-11-16 Nathan Froyd + + * lto.c (lto_read_base_type_DIE): Use make_bitfield_integer_type to + construct the integer type for bitfields. + +2007-11-16 Kenneth Zadeck + + * lto-read.c (data_in.current_node_has_loc): Removed. + (input_line_info): Returns true if node needs line set. + (set_line_info): Always sets line if called. + (clear_line_info): Removed reference to current_node_needs_loc. + (input_expr_operand): Keeps track locally if current node needs a loc. + (input_local_var): Added code to handle DECL_INITIAL for + static local vars. Only set loc if necessary. + +2007-11-15 Nathan Froyd + + * lto.c (lto_read_subroutine_type_subprogram_DIE): Fix thinko'd + DECL_CONTEXT. + +2007-11-15 Nathan Froyd + + * lto.c: Include langhooks.h. + (lto_find_integral_type): Rework logic to handle the case where + got_byte_size is true, but the bitsize requested and that of the + base_type doesn't match. + (lto_read_variable_formal_parameter_constant_DIE): Only check for + asm_name if we are creating a VAR_DECL. + (lto_materialize_function): Set DECL_EXTERNAL if we can't find a + definition. + (lto_read_subroutine_type_subprogram_DIE): Check for a builtin + function reference and use the builtin's decl if so. Set the + DECL_CONTEXT of the RESULT_DECL for the function. + * lto-lang.c (registered_builtin_fndecls): New variable. + (lto_getdecls): Return it. + (lto_builtin_function): Chain the new decl onto + registered_builtin_fndecls. + +2007-11-15 Kenneth Zadeck + + * lto-read.c (process_tree_flags, lto_static_init_local): + Renamed to ADD_CLASS_EXPR_FLAG. ADD_CLASS_DECL_FLAG New Macro. + (input_line_info, clear_line_info): Fixed new line number code. + (input_expr_operand): Added type to SWITCH_EXPR. + (lto_read_body): Properly initialized data_in. + Clear line info when leaving. + +2007-11-13 Diego Novillo + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): + Initialize ARTIFICIAL. + (lto_read_subroutine_type_subprogram_DIE): Initialize + SAVED_SCOPE. + * lto-read.c (set_line_info): Remove ; from calls to + LINEMAP_POSITION_FOR_COLUMN. + +2007-11-13 Kenneth Zadeck + + * lto-read.c (input_type_ref): Renamed from get_type_ref. + (input_expr_operand, input_local_var): Renamed get_type_ref to + input_type_ref. + (input_expr_operand): Get the types correct for + vector-cst. Get SSA_NAME_DEF_STMT correct for return_exprs. + +2007-11-13 Doug Kwan + + * lto-read.c (input_widest_uint_uleb128): New function. + (input_tree_flags, process_tree_flags, input_line_info, + input_expr_operand, input_local_var, input_phi, input_ssa_names): + Change to use lto_flags_type and BITS_PER_LTO_FLAGS_TYPES instead of + unsigned HOST_WIDE_INT and HOST_BITS_PER_WIDE_INT. + (lto_static_init_local): Add code to assert that lto_flags_type is + wide enough. + +2007-11-13 Nathan Froyd + + * lto.c (lto_read_array_type_DIE): Handle DW_AT_GNU_vector. + (lto_read_subroutine_type_subprogram_DIE): Handle + DW_AT_static_link and DW_AT_specification. Return the + specification if present. + (lto_read_base_type_DIE): Handle DW_ATE_complex_float. + +2007-11-13 Nathan Froyd + + * lto-lang.c: Include target.h. + (registered_builtin_types): New variable. + (lto_type_for_mode): Increase number of modes handled. + (lto_builtin_function): Fix argument list and return the decl. + (lto_register_builtin_type): New function. + (lto_init): Initialize target builtins and language-independent + nodes. + (LANG_HOOKS_REGISTER_BUILTIN_TYPE): Define. + +2007-11-13 Kenneth Zadeck + + * lto-read.c (input_expr_operand): Added code to properly handle + index filed. Added new RANGE_EXPR case. + +2007-11-11 Kenneth Zadeck + + * lto-read.c (ADD_FUNC_FLAG): Deleted macro. + (data_in): Added current_node_has_loc field. + (input_line_info, set_line_info, clear_line_info): Added a support + for USE_MAPPED_LOCATION and not adding line numbers to nodes that + did not have on on the source side. + (input_expr_operand): Make sure that GIMPLE_MODIFY_STMTS get line + numbers too. + +2007-11-09 Doug Kwan + + * lto-read.c (input_expr_operand): Change type of operand 2 of + BIT_FIELD_REF expression to be bitsizetype instead of sizetype. + +2007-11-09 Nathan Froyd + + * lto.c: Include lto-tree.h. Effect small spaces->tabs cleanup. + (lto_read_variable_formal_parameter_constant_DIE): Transfer bits + from a DW_AT_specification or DW_AT_abstract_origin attribute to + the new decl we are creating. Move informing the middle end about + the new decl to... + (lto_main): ...here. Inform the middle end about global variables + after we have read in all the input files. + * lto-symtab.c (lto_symtab_merge_decl): We really do need to merge + variables with internal linkage, so delete the check for internal + linkage. Combine TREE_PUBLIC flags. + +2007-11-08 Nathan Froyd + + * lto.c (lto_read_subroutine_type_subprogram_DIE): Handle + DW_AT_decl_line. + * lto-symtab.c (lto_symtab_merge_decl): Handle redefinition of a + builtin specially. Move check for attribute compatibility + earlier. + +2007-11-07 Nathan Froyd + + * Make-lang.in (lto/lto.o): Depend on gt-lto-lto.h. + * config-lang.in (gtfiles): Add lto.h and lto.c. + * lto-elf.c: Include ggc.h. + (lto_elf_file_open): Allocate elf_file from GC memory. + * lto.c: Include tree-ssa-operands.h and gt-lto-lto.h + (lto_info_fd_init): Allocate the die_cache and unmaterialized_fndecls + in GC memory. + (lto_info_fd_close): Free unmaterialized_fndecls from GC memory. + (lto_file_close): Free file from GC memory. + (lto_cache_store_DIE): Allocate the new entry in GC memory. + (lto_read_member_DIE): Fix declaration. + (lto_read_subroutine_type_subprogram_DIE): unmaterialized_fndecls lives + in GC memory. + (current_lto_file): New variable. + (lto_main): Use it. + (DWARF2_attr, DWARF2_abbrev, lto_die_ptr, DWARF2_CompUnit, + lto_die_cache_entry): Move to... + * lto.h: ...here and add GTY markers as appropriate. Delete forward + declarations accordingly. + (struct lto_file_struct): Declare. + (lto_file_vtable): Use it instead of lto_file. + +2007-11-06 Alon Dayan + Kenneth Zadeck + + * lto-read.c (process_flags, lto_static_init_local): + read flags of VAR_DECL and FUNCTION_DECL of size>1. + change global array num_flags_for_code to flags_length_for_code. + (set_line_info): Make decls work in USE_MAPPED_LOCATION mode. + +2007-11-05 Nathan Froyd + + * lto.c (lto_read_structure_union_class_type_DIE): Use proper record + layout functions to compute information about the newly constructed + type. + +2007-11-02 Nathan Froyd + + * lto-read.c (input_expr_operand): Change the LTO_return_expr1 + case to use DECL_RESULT if necessary. + +2007-11-01 Kenneth Zadeck + + * lto-read.c (input_tree_list): Removed. + (input_tree_flags): Added parameter to force flags no matter what + tree code. + (input_expr_operand): Added parameter to input_tree_flags. + Added case for IDENTIFIER_NODE and TREE_LIST. Changed ASM to call + input_expr_operand rather than input_tree_lists. + (input_local_var): Use input_expr_operand to read attributes + rather then input_tree_list. + (input_phi, input_ssa_names): Added parameter to input_tree_flags. + +2007-10-31 Nathan Froyd + + * lto.c (lto_read_typedef_DIE): Fix comment typo. + (lto_resolve_typedecl_ref): Fetch the referred-to type and build a fake + TYPE_DECL for it. + * lto-read.c (lto_read_body): Use correct sizes for calculating + type_decls_offset and types_offset. + +2007-10-30 Nathan Froyd + + * lto-tree.h (union lang_tree_node): Change GTY description to chain + with GENERIC_NEXT. + * config-lang.in (gtfiles): Add lto-lang.c. + * lto-lang.c: Include gt-lto-lto-lang.h. + * Make-lang.in (lto/lto-lang.o): Add dependency on gt-lto-lto-lang.h + (lto/lto-symtab.o): Depend on LTO_H instead of TREE_H. + (lto/lto-read.o): Likewise. + +2007-10-29 Kenneth Zadeck + + * lto-read.c (data_in): Added type_decls and current_col fields. + (string_slot): New type to hold canonized file name. + (hash_string_slot_node, eq_string_slot_node, canon_file_name, + input_line_info, set_line_info, clear_line_info): New functions. + (file_name_hash_table): New hash table. + (input_local_var, input_labels, input_local_vars_index, + input_local_var, input_local_vars, input_ssa_names): Reorganized parameters. + (input_uleb128): Changed type of byte var. + (input_expr_operand): Large number of changes to get line numbers + correct. Added TYPE_DECL case. + (input_globals): Added code to get TYPE_DECLs processed. + (input_local_var): Added code to process line numbers and + TREE_CHAIN and DECL_CONTEXT. + (input_function, input_constructor): Added call to + clear_line_number. + (lto_static_init_local): Added code to get line numbers correct. + (lto_read_body): Added code to get TYPE_DECLS read and to change + parameters to the calls above that had their parms reorganized. + + +2007-10-29 Nathan Froyd + + * lto.h (lto_resolve_typedecl_ref): Declare. + * lto.c (lto_resolve_typedecl_ref): New function. + +2007-10-29 Mark Mitchell + Nathan Froyd + + * lto.c (lto_read_subroutine_type_subprogram_DIE): Read the child + DIEs even if we find an abstract origin for this DIE. + +2007-10-29 Nathan Froyd + + * lto.c (lto_read_subroutine_type_subprogram_DIE): Build the + RESULT_DECL slightly earlier. Only remember the decl for later + if we successfully merge declarations. + +2007-10-24 Kenneth Zadeck + + * lto-read.c (input_expr_operand): Give label_values the proper + context and provide switch statements with a default type. + +2007-10-23 Nathan Froyd + + * lto-read.c (lto_read_body): Move call to init_ssa_operands... + * lto.c (lto_materialize_function): ...to here. + +2007-10-22 Nathan Froyd + + * lto.h (struct lto_info_fd): Add field unmaterialized_fndecls. + * lto.c (lto_info_fd_init): Initialize it. + (lto_info_fd_close): Free it. + (lto_materialize_function): New function. + (lto_read_subroutine_type_subprogram_DIE): Save the result decl on + unmaterialized_fndecls. + (lto_file_read): Read in all the function bodies after we have read + all of the DWARF info. + * lto-read.c (lto_read_body): Call init_ssa_operands if we are + reading a function body. + +2007-10-20 Kenneth Zadeck + + * lto-read.c (input_tree_flags): Renamed from input_flags to be + semetric with output_tree_flags. Added call to log flags. + (process_tree_flags): Renamed from process_flags. Fixed a lot of + type issues to make everything consistent with flags being + unsigned HOST_WIDE_INTS. + (input_expr_operand): Added call to + recompute_tree_invariant_for_addr_expr. + (input_local_var): Added debugging for tree_chains. Now calls + input_tree_flags. + (input_phi): Made flags unsigned HOST_WIDE_INT. + (input_ssa_names): Now calls input_tree_flags. + (lto_read_body): Now sets cfun. + (lto_read_function_body): Now sets current_function_pointer. + +2007-10-19 Nathan Froyd + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Check + definitively whether SPECIFICATION or ABSTRACT_ORIGIN exist before + inspecting fields within. + (lto_read_DIE_at_ptr): Delete check for null result; let callers + handle this appropriately. + +2007-10-19 Nathan Froyd + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Handle + DW_AT_abstract_origin properly. Ensure that we're not dealing with + both DW_AT_abstract_origin and DW_AT_specification. + (lto_read_subroutine_type_subprogram_DIE): Handle + DW_AT_abstract_origin. + (lto_read_DIE): Use lto_read_only_for_child_DIEs for labels. + (lto_read_DIE_at_ptr): Define as static to match declaration. + Lookup the PTR in the cache before reading it from the file. + (lto_resolve_var_ref): Adjust accordingly. + (lto_resolve_fn_ref): Adjust accordingly. Tweak comment. + (lto_resolve_field_ref): Adjust accordingly. Tweak comment. + +2007-10-19 Nathan Froyd + + * lto.c (lto_read_DIE_at_ptr): New function. + (lto_resolve_var_ref): Use it. + (lto_resolve_fn_ref): Use it. + (lto_resolve_field_ref): Use it. + (lto_read_variable_formal_parameter_constant_DIE): Follow + DW_AT_specification and return the associated decl when appropriate. + +2007-10-18 Nathan Froyd + + * lto-lang.c (lto_type_for_mode): Move after lto_type_for_size. + Implement for scalar integer modes. + (lto_init): Initialize size_type_node. + +2007-10-18 Kenneth Zadeck + + * lto-read.c (input_expr_operand): Remove ssa name asserts. + (input_local_var): Add chaining for params. + (input_ssa_names): Add cfun parameter. + (input_function): Remove unnecessary else. + +2007-10-17 Nathan Froyd + + * lto.c (lto_read_only_for_child_DIEs): Mark die parameter as unused. + (lto_resolve_var_ref): Use proper types. + (lto_resolve_fn_ref): Likewise. + (lto_resolve_field_ref): Likewise. + +2007-10-17 Nathan Froyd + + * lto-read.c (input_expr_operand): Remove case. + +2007-10-17 Nathan Froyd + + * lto.c (lto_read_only_for_child_DIEs): New function. + (lto_read_DIE): Use it for lexical_block and inlined_subroutine DIEs. + * lto-elf.c (lto_elf_map_lto_section): Remove. + (lto_elf_file_vtable): Use lto_elf_map_optional_lto_section instead. + * lto-read.c (input_expr_operand): Assert that we never read a NULL + SSA_NAME. Add missing case for mechanical codes. + (input_cfg): Use basic_block_info_for_function instead of + basic_block_info. + +2007-10-16 Kenneth Zadeck + + * lto-read.c (input_sleb128, input_integer): Use proper casts. + (input_list): Renamed input_tree_list and modified to follow same + protocol as lto-function-out.c:output_tree_list. + (input_expr_operand): Make asm operands use input_tree_list. + (input_local_var): Now uses input_tree_list. + (lto_read_body): Change placement for setting context of debug_labels. + + +2007-10-16 Kenneth Zadeck + + * lto-read.c (input_real): Output debugging in proper order. + (input_integer): Compute bit lengths properly. + (input_list): Clean up declaration. + (input_expr_operand): Change calls to input_real to match fix. + Make reading of LTO_bit_field_ref1 match output. + (input_local_var): Make reading of attributes match what is being + written. + (dump_debug_stream): Also print char in hex. + (debug_out_fun): Fix signed unsigned mismatch. + +2007-10-10 Nathan Froyd + + * lto.c (lto_read_form): Handle DW_AT_MIPS_linkage_name and + DW_AT_GNU_vector specially, as they are not contiguous with the + specified set of attribute names. Use class_mask to check for + errors at the end of the function + (lto_resolve_var_ref): Read the DIE if it is not cached. + (lto_resolve_fn_ref): Likewise. + (lto_resolve_field_ref): Likewise. + +2007-10-05 Nathan Froyd + + * lto.c: Include dwarf2out.h. + (lto_cache_store_DIE): Assert that we never change the value. + (LTO_BEGIN_READ_ATTRS): Print an informative error message. + (lto_read_compile_unit_DIE): Handle DW_AT_entry_pc. + (lto_read_array_type_DIE): Don't error on ndims == 0; build a + sensible type instead. + (lto_read_structure_union_class_type_DIE): Store the newly + created type prior to reading the members of the structure to + avoid infinite recursion. Avoid computing types and alignments + for structures whose sizes are unknown. + (lto_read_variable_formal_parameter_const): Handle DW_AT_artificial + and set DECL_ARTIFICIAL accordingly. Ignore DW_AT_abstract_origin, + DW_AT_const_value, and DW_AT_specification. + (lto_read_subroutine_type_subprogram_DIE): Handle DW_AT_declaration. + Return early if we have already constructed the function type. + (lto_read_typedef_DIE): Check to see if the type has been cached + already. Cache the type before reading any children. + (lto_read_const_volatile_restrict_type_DIE): Handle DW_AT_name. + (lto_read_DIE): Unset context->skip_non_parameters around reading + the DIE. + (lto_resolve_fn_ref): Delete trailing whitespace. + +2007-09-11 Kenneth Zadeck + + * lto-read.c (input_expr_operand): Added type for STRING_CST. + +2007-09-10 Nathan Froyd + + * lto-read.c (lto_read): Set the type of the newly created CALL_EXPR. + +2007-09-07 Nathan Froyd + + * lto-lang.c (signed_and_unsigned_types): New variable. + (lto_type_for_size): Consult signed_and_unsigned_types to find + an approprite type, creating it if necessary. + (lto_set_decl_assembler_name): Add actual method body. + +2007-09-06 Jim Blandy + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): If we + can't find a var init for this variable, leave its DECL_INITIAL. + * lto-elf.c (lto_elf_map_optional_lto_section): Renamed from + lto_elf_map_fn_body. + (lto_map_lto_section): New function. + (lto_elf_file_vtable): Use lto_elf_map_lto_section for function + bodies, and lto_elf_map_optional_lto_section for variable + initializers. + (lto_elf_find_section_data): Quietly return NULL if the section is + missing. + (lto_elf_file_open): Check for a NULL from lto_elf_find_section_data. + + * lto-elf.c (lto_elf_find_section_data): Remove dead code. + + * lto-read.c (lto_read_body): Doc fix. + +2007-08-29 Kenneth Zadeck + + * lto-read.c (fun_in): Renamed to data_in. + (input_expr_operand, input_local_var, input_string_internal, + input_string, input_real, input_list, get_label_decl, + get_type_ref, input_expr_operand, input_globals, input_labels, + input_local_vars_index, input_local_var, input_local_vars, + input_cfg, input_phi, input_ssa_names, input_bb, ): Renamed fun_in to data_in. + (input_constructor): New function. + (lto_read_function_body): Renamed to lto_read_body and generalized + to handle both functions and constructors. + (lto_read_function_body, lto_read_var_init): New function. + + +2007-08-28 Kenneth Zadeck + + * lto-read.c (input_expr_operand): Assert that there really is a + FUNCTION_DECL. + (input_globals): Removed checks on 0 section. + +2007-08-28 Kenneth Zadeck + + * lto-read.c (fun_in): Added local_decls_index and + local_decls_index_d. + (input_expr_operand): Changed inputting of PARM_DECLs and VAR_DECLs. + (input_globals): Enabled code to handle FIELD_DECLs. + (input_local_vars_index, input_local_vars): New function. + (input_local_var): Changed to allow locals to be input randomly. + (lto_read_function_body): Added code to input the + local_decls_index and to free various structures. + +2007-08-17 Jim Blandy + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Remove + ATTRIBUTE_UNUSED from 'die' formal. + + Use enum LTO_tags where appropriate, instead of 'unsigned int'. + * lto-read.c (input_record_start): Fix return type, type of 'tag'. + (input_list): Fix type of 'tag'. + (input_expr_operand): Fix type of 'tag' argument. Update + declaration. Fix type of 'ctag'. Add default case to switch, + since the type of the switched value is now an enum. + (input_local_vars): Fix type of 'tag'. + (input_bb): Fix type of 'tag' argument. + (input_function): Fix type of 'tag' argument. + +2007-08-16 Jim Blandy + + * lto.c (lto_read_member_DIE): Record the tree we create in + fd->die_cache. (Our 'die' argument is no longer unused.) + (lto_resolve_field_ref): New function. + * lto.h (lto_resolve_field_ref): New declaration. + +2007-08-15 Jim Blandy + + * lto-read.c (lto_read_var_init): Mark arguments as unused. + +2007-08-07 Jim Blandy + + * lto.c (lto_read_form): Complete attr_classes table. + (DWARF2_form_data): Doc fix. + +2007-08-05 Mark Mitchell + + * lto.h (lto_file_vtable): Remove read_var_init. Add map_var_init + and unmap_var_init. + (lto_read_var_init): Declare. + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Use new + interface for reading variable initializers. + * lto-elf.c (lto_elf_read_var_init): Remove. + (lto_elf_file_vtable): Update initializer. + (lto_elf_read_var_init): Add comment about unused-ness. + * lto-read.c (lto_read_var_init): New. + + * lto.c (lto_read_form): Add entry for DW_AT_inline. + +2007-08-02 Kenneth Zadeck + + * lto-read.c (lto_read_function_body): Moved declaration of fn + outside of ifdef. + +2007-08-01 Kenneth Zadeck + + * lto-read.c (input_uleb128, input_string_internal, input_real, + input_integer, input_record_start, input_list, get_type_ref, + input_flags, input_expr_operand, input_expr_operand, + input_expr_operand, input_local_vars, input_cfg, input_phi, + input_ssa_names, input_bb, input_function): Added semicolons. + + +2007-07-31 Kenneth Zadeck + + * lto-read.c (input_globals): Remove debugging. + (input_function): Set DECL_ARGUMENTS. + + +2007-07-31 Kenneth Zadeck + + * lto-read.c (input_expr_operand): Fixed code for COND_EXEC, + RETURN_EXPR, MODIFY_EXPR and processing of flags. + (input_phi): Made work with operands other than SSA_NAMES and + fixed processing of flags. + (input_ssa_names): Initialize SSA_NAME_DEF_STMT to empty stmt. + (input_flags): New function. + * lto-lang.c (lto_init): Changed state of in_lto_p. + + +2007-07-24 Mark Mitchell + + * lto-tree.h (lto_varargs_cookie): Remove. + * lto.c (lto_context): Add last_parm_type, varargs_p, skip_all, + skip_non_parameters, skip_parameters. + (lto_varargs_cookie): Remove. + (lto_read_variable_formal_parameter_constant_DIE): Keep track of + parameter types. + (lto_read_abbrev): New function. + (lto_read_subroutine_type_subprogram_DIE): Make two passes over + child DIEs. + (lto_read_unspecified_parameters_DIE): Set context->varargs_p. + (lto_read_DIE): Use lto_read_abbrev. Honor skip_* flags. + (lto_file_read): Initialize new context fields. + * lto-lang.c (lto_type_for_mode): Return NULL_TREE. + (lto_unsigned_type): Remove. + (lto_signed_type): Likewise. + (lto_signed_or_unsigned_type): Likewise. + (lto_init): Do not create lto_varargs_cookie. + (LANG_HOOKS_UNSIGNED_TYPE): Do not define. + (LANG_HOOKS_SIGNED_TYPE): Likewise. + (LANG_HOOKS_SIGNED_OR_UNSIGNED_TYPE): Likewise. + +2007-07-19 Jan Hubicka + + * lto-read.c (lto_read_function_body): Produce empty scope block + to avoid crash. + +2007-07-18 Mark Mitchell + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Do not + process local variables. + (lto_read_subroutine_type_subprogram_DIE): Read child DIEs. + +2007-07-13 Kenneth Zadeck + + * lto-read.c (input_list, input_expr_operand): Added struct + function parameter. + (init_cfg, finalize_cfg): Removed function. + (input_expr_operand): Added SSA_NAME and GIMPLE_MODIFY_STMT cases. + (input_labels, input_local_vars): Now takes input_block parameter rather than + synthsyzing it. + (input_cfg, input_phi, input_ssa_names): New functions. + (input_bb): Now passes in input_blocks. Does not construct cfg + and processes the list of phi functions. + (input_function): Now builds both the cfg and ssa_names table. + (lto_read_function_body): Processes new header fields to construct + streams for the ssa_names and cfg and their debugging. + * lto/lto-lang.c (lto_init): Set in_lto_p. + + +2007-06-28 Mark Mitchell + + * lto.h (lto_file_vtable): Add read_var_init. + * lto.c (lto_read_variable_formal_parameter_constant_DIE): Read + initializers. + (lto_main): Remove bogus asserts. + * lto-elf.c (tm.h): Include it. + (libiberty.y): Likewise. + (lto_elf_file): Add strtab and symtab. Rename + string_table_section_index to sec_strtab. + (lto_elf_file_vtable): Add lto_elf_read_var_init. + (lto_elf_get_shdr): New function. + (lto_elf_free_shdr): Likewise. + (lto_elf_find_section_data): Use them. + (lto_elf_read_symtab): New function. + (lto_elf_lookup_sym): Likewise. + (lto_elf_free_sym): Likewise. + (lto_elf_file_open): Tidy. Call lto_elf_read_symtab. + (lto_elf_built_init): New function. + (lto_elf_read_var_init): Likewise. + * Make-lang.in (lto/lto-elf.o): Depend on $(TM_H). + +2007-06-26 Kenneth Zadeck + + * lto-read (make_new_block): Initialize the stmt_list. + (lto_static_init_local): Add debugging for missing codes. + +2007-06-26 Mark Mitchell + + * lto.c (lto_read_subroutine_type_subprogram_DIE): Handle + unprototyped functions. + +2007-06-23 Mark Mitchell + + * lto.c (lto_read_variable_formal_parameter_constant_DIE): + Handle DW_AT_MIPS_linkage_name. + (lto_read_subroutine_type_subprogram): Likewise. Correct + compilation errors. + (lto_main): Remove incorrect assertions. + * lto-symbtab.c: Build function types out of TREE_LISTs. + + * lto-elf.c (): Check for HAVE_LIBELF_H. + + * Make-lang.in (LTO_OBJS): Depend on attribs.o. + +2007-06-21 Kenneth Zadeck + + * lto/lto-tree.h (lang_decl, lang_type, language_function): Added + dummy since ggc does not like empty structs. + * lto/lto-elf.c (libelf.h): Changed to libelf/libelf.h. + * lto/lto-read.c (ADD_CLASS_FLAG, ADD_EXPR_FLAG): Changed + expr->common to expr->base. + (make_new_block): Moved stmt_list to proper place. + + +2007-03-14 Robert Kennedy + + Eliminate use of lang_hooks.set_decl_assembler_name from LTO + * lto.c (lto_read_subroutine_type_subprogram_DIE) Get DECL + assembler name from DWARF. + * lto-lang.c (lto_set_decl_assembler_name) New function. + +2006-09-10 Mark Mitchell + + * lto.h (lto_file_vtable): New structure. + (lto_file): Add vtable pointer. + (lto_file_init): Add vtable paramter. + (lto_read_function_body): New function. + (lto_symtab_merge_fn): New function. + * lto.c (lto_file_init): Add vtable parameter. + (lto_read_form): Fill in entries for DW_AT_prototyped, + DW_AT_frame_base. + (lto_read_subroutine_type_subprogram_DIE): New function. + (lto_read_DIE): Fill in entries for DW_TAG_subroutine_type and + DW_TAG_subprogram. + * lto-elf.c (lto_elf_vile_vtable): New variable. + (lto_elf_file_open): Pass it to lto_file_init. + (lto_elf_map_fn_body): New function. + (lto_elf_unmap_fn_body): Likewise. + * lto-read.c: New file. + * lto-symtab.c (lto_symtab_merge_fn): New function. + * lto-lang.c (LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION): Define to + tree_rest_of_compilation. + * Make-lang.in (LTO_OBJS): Add lto-read.o + (lto-read.o): New target. + +2006-09-03 Mark Mitchell + + * lto.c (): Don't include it. + (lto_context): Don't typedef it. + (lto_resolve_reference): New function. + (lto_read_form): Use it. + (lto_resolve_type_ref): New function. + (lto_resolve_var_ref): Likewise. + (lto_resolve_fn_ref): Likewise. + * lto.h (): Include it. + (lto_context): New type. + (lto_ref): New structure. + (lto_resolve_type_ref): Declare. + (lto_resolve_var_ref): Likewise. + (lto_resolve_fn_ref): Likewise. + +2006-08-18 Mark Mitchell + + * lang-specs.h: New file. + +2006-08-14 Mark Mitchell + + * lto.c (lto_info_fd_init): Allocate the DIE cache. + (lto_info_fd_close): Deallocate it. + (lto_die_cache_entry): New structure. + (lto_cache_hash): New function. + (lto_cache_eq): Likewise. + (lto_cache_store_DIE): Likewise. + (lto_cache_lookup_DIE): Likewise. + (lto_read_referenced_type_DIE): Use the cache. + (lto_read_pointer_type_DIE): Robustify. + (lto_read_DIE): Use the cache. + * lto.h (hashtab.h): Include. + (lto_info_fd): Add DIE cache. + * Make-lang.in (LTO_H): New variable. + (lto/lto-lang.o): Use LTO_H. + (lto/lto-elf.o): Likewise. + (lto/lto-symtab.o): Likewise. + +2006-07-09 Mark Mitchell + + * lto.c (lto_abi_mismatch_error): New function. + (lto_abbrev_read): Initialize num_abbrevs. + (lto_read_form): Specify allowed form classes for + DW_AT_declaration. Adjust for change to lto_set_cu_context. + (lto_read_variable_formal_parameter_constant_DIE): Handle + DW_AT_declaration. Call lto_symtab_merge_var. + (lto_read_pointer_type_DIE): New function. + (lto_read_base_type_DIE): Use build_nonstandard_integer_type. Do + not creat TYPE_DECLs for types that already have them. + (lto_read_DIE): Add lto_read_pointer_type_DIE. + (lto_set_cu_context): Make cu_start point to the header, not the + first DIE. + (lto_file_read): Adjust for change to lto_set_cu_context. + * Make-lang.in (LTO_OBJS): Add lto-symtab.o. + (lto/lto-symtab.o): New rule. + * lto-tree.h (lang_identifier): Add decl field. + (LANG_IDENTIFIER_CAST): New macro. + (LTO_IDENTIFIER_DECL): Likewise. + (lto_symtab_merge_var): Declare. + * lto-symtab.c: New file. + +2006-07-02 Daniel Berlin + + * lto.c (lto_context): Add current_cu and info_fd members. + (DWARF2_CompUnit): New structure. + (lto_read_DIE): Take lto_info_fd *. + (lto_read_child_DIEs): Ditto. + (lto_file_corrupt_error): Constify argument. + (lto_set_cu_context): New function + (lto_info_fd_init): Ditto. + (lto_info_fd_close): Ditto. + (lto_file_init): Use lto_info_fd_init. + (lto_file_close): Use lto_info_fd_close. + (lto_read_initial_length): Pass in pointer to header size. + (lto_read_comp_unit_header): Correct cu_length to + real length from beginning of header. Take lto_info_fd * as + argument. + (find_cu_for_offset): New function. + (lto_read_form): Change first argument to lto_info_fd *. + Add FORM_CONTEXT argument. + Handle DW_FORM_ref_addr. + (lto_read_tag_DIE): Change first argument to lto_info_fd *. + (LTO_BEGIN_READ_ATTRS_UNCHECKED): Save old context. + Swap contexts if necessary for form. + (LTO_BEGIN_READ_ATTRS): Cast fd to right type for + lto_file_corrupt_error. + (LTO_END_READ_ATTRS): Swap contexts back if it had changed. + (lto_read_referenced_type_DIE): Change first argument to + lto_info_fd *. Access lto_fd fields through base pointer. + (lto_read_compile_unit_DIE): Change first argument to an + lto_info_fd *. + (lto_read_variable_formal_parameter_constant_DIE): Ditto. + (lto_read_base_type_DIE): Ditto. + (lto_read_child_DIEs): Ditto. + (lto_read_DIE): Ditto. Change type of function pointer. + (lto_info_read): New function. + (lto_set_cu_context): Ditto. + (lto_file_read): Use lto_info_read, walk resulting CU's + (lto_main): Update for lto_info_fd change. + * lto-elf.c (lto_elf_file_open): Cast lto_info_fd to lto_fd where + necessary. + * lto.h (DWARF2_CompUnit): New structure. + (lto_info_fd): Ditto. + (lto_file): Change debug_info to be an lto_info_fd. + +2006-06-25 Mark Mitchell + + * lto.c (toplev.h): Include it. + (dwarf2.h): Likewise. + (tree.h): Likewise. + (tm.h): Likewise. + (cgraph.h): Likewise. + (ggc.h): Likewise. + (inttypes.h): Likewise. + (DWARF2_attr): New type. + (DWARF2_abbrev): Likewise. + (DWARF2_class): Likewise. + (DWARF2_form_data): Likewise. + (lto_context): Likewise. + (lto_fd_init): New function. + (lto_abbrev_fd_init): Likewise. + (lto_abbrev_fd_close): Likewise. + (lto_file_init): Use them. + (lto_file_close): New function. + (lto_file_corrupt_error): Likewise. + (LTO_CHECK_INT_VAL): New macro. + (lto_check_size_t_val): New function. + (lto_check_int_val): Likewise. + (LTO_READ_TYPE): New macro. + (lto_read_ubyte): New function. + (lto_read_uhalf): Likewise. + (lto_read_uword): Likewise. + (lto_read_uleb128): Likewise. + (lto_read_initial_length): Likewise. + (lto_abbrev_read_attrs): Likewise. + (lto_abbrev_read): Likewise. + (lto_abbrev_lookup): Likewise. + (lto_read_section_offset): Likewise. + (lto_read_comp_unit_header): Likewise. + (lto_read_form): Likewise. + (LTO_BEGIN_READ_ATTRS_UNCHECKED): New macro. + (LTO_BEGIN_READ_ATTRS): Likewise. + (LTO_END_READ_ATTRS): Likewise. + (lto_unsupported_attr_error): New function. + (lto_get_identifier): Likewise. + (lto_read_referenced_type_DIE): Likewise. + (lto_read_compile_unit_DIE): Likewise. + (lto_read_variable_formal_parameter_constant_DIE): Likewise. + (lto_read_base_type_DIE): Likewise. + (lto_read_DIE): Likewise. + (lto_read_child_DIEs): Likewise. + (lto_file_read): Read DIEs. + (lto_main): Ask middle end to emit entities. + * lto-tree.h (lang_identifier): Inherit from tree_identifier. + * lto-elf.c (lto_elf_file_open): Adjust for interface changes. + (lto_elf_file_close): Likewise. + * lto.h (lto_file): Declare. + (DWARF2_abbrev): Likewise. + (lto_fd): New type. + (lto_abbrev_fd): Likewise. + (lto_file): Use new types. + (lto_file_close): Declare. + * lto-lang.c (lto_init): Always use unit-at-a-time mode. + +2006-06-18 Mark Mitchell + + * lto.h: New file. + * lto.c: New file. + * lto-elf.c: New file. + * lto-lang.c (flags.h): Include it. + (lto.h): Likewise. + (lto_init): New function. + (lto_write_globals): Remove. + (LANG_HOOKS_WRITE_GLOBALS): Define to lhd_do_nothing. + (LANG_HOOKS_INIT): Define. + (LANG_HOOKS_PARSE_FILE): Likewise. + * Make-lang.in (LTO_OBJS): Add lto.o and lto-elf.o. + (LTO_EXE): Link with libelf. + (lto/lto-lang.o): Update dependencies. + (lto/lto.o): New target. + (lto/lto-elf.o): Likewise. + +2006-06-12 Mark Mitchell + + * config-lang.in: New file. + * Make-lang.in: Likewise. + * lto-tree.h: Likewise. + * lto-lang.c: Likewise. + diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in new file mode 100644 index 00000000000..1dcaace1ade --- /dev/null +++ b/gcc/lto/Make-lang.in @@ -0,0 +1,89 @@ +# Top level -*- makefile -*- fragment for LTO +# Copyright (C) 2009 +# 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 3, 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 COPYING3. If not see +# . + +# Variables + +# The name of the LTO compiler. +LTO_EXE = lto1$(exeext) +# The LTO-specific object files inclued in $(LTO_EXE). +LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o attribs.o +LTO_H = lto/lto.h $(HASHTAB_H) +LINKER_PLUGIN_API_H = $(srcdir)/../include/plugin-api.h +LTO_TREE_H = lto/lto-tree.h $(LINKER_PLUGIN_API_H) + + +# Rules + +# These hooks are used by the main GCC Makefile. Consult that +# Makefile for documentation. +lto.all.cross: $(LTO_EXE) +lto.start.encap: $(LTO_EXE) +lto.rest.encap: +lto.tags: +lto.install-common: +lto.install-man: +lto.install-info: +lto.dvi: +lto.pdf: +lto.install-pdf: +lto.html: +lto.uninstall: +lto.info: +lto.man: +lto.srcextra: +lto.srcman: +lto.srcinfo: +lto.install-plugin: + +lto.mostlyclean: + rm -f $(LTO_OBJS) $(LTO_EXE) + +lto.clean: +lto.distclean: +lto.maintainer-clean: +lto.stage1: +lto.stage2: +lto.stage3: +lto.stage4: +lto.stageprofile: +lto.stagefeedback: + +# LTO rules. + +# Use strict warnings for this front end. +lto-warn = $(STRICT_WARN) + +$(LTO_EXE): $(LTO_OBJS) $(BACKEND) $(LIBDEPS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \ + $(LTO_OBJS) $(BACKEND) $(BACKENDLIBS) $(LIBS) -lelf + +# Dependencies +lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \ + flags.h $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(SYSTEM_H) \ + $(TARGET_H) $(LTO_H) $(GIMPLE_H) gtype-lto.h gt-lto-lto-lang.h \ + $(EXPR_H) +lto/lto.o: lto/lto.c $(CONFIG_H) $(SYSTEM_H) coretypes.h opts.h \ + toplev.h $(TREE_H) $(DIAGNOSTIC_H) $(TM_H) $(LIBIBERTY_H) \ + $(CGRAPH_H) $(GGC_H) tree-ssa-operands.h $(TREE_PASS_H) \ + langhooks.h vec.h $(BITMAP_H) pointer-set.h $(IPA_PROP_H) \ + $(COMMON_H) $(TIMEVAR_H) $(GIMPLE_H) $(LTO_H) $(LTO_TREE_H) \ + $(LTO_TAGS_H) $(LTO_STREAMER_H) +lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \ + toplev.h $(LTO_H) $(TM_H) $(LIBIBERTY_H) $(GGC_H) $(LTO_STREAMER_H) diff --git a/gcc/lto/common.c b/gcc/lto/common.c new file mode 100644 index 00000000000..b54ec491e12 --- /dev/null +++ b/gcc/lto/common.c @@ -0,0 +1,46 @@ +/* Common code for the plugin and lto1. + Copyright (C) 2009 Free Software Foundation, Inc. + Contributed by Rafael Avila de Espindola (espindola@google.com). + +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 3 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., 51 Franklin Street - Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include "common.h" + +const char *lto_kind_str[5] __attribute__ ((visibility ("hidden"))) = +{ + "DEF", "WEAKDEF", "UNDEF", + "WEAKUNDEF", "COMMON" +}; + +const char *lto_visibility_str[4] __attribute__ ((visibility ("hidden"))) = +{ + "DEFAULT", "PROTECTED", + "INTERNAL", "HIDDEN" +}; + +const char *lto_resolution_str[9] __attribute__ ((visibility ("hidden"))) = +{ + "UNKNOWN", + "UNDEF", + "PREVAILING_DEF", + "PREVAILING_DEF_IRONLY", + "PREEMPTED_REG", + "PREEMPTED_IR", + "RESOLVED_IR", + "RESOLVED_EXEC", + "RESOLVED_DYN" +}; + diff --git a/gcc/lto/common.h b/gcc/lto/common.h new file mode 100644 index 00000000000..e82184795ba --- /dev/null +++ b/gcc/lto/common.h @@ -0,0 +1,34 @@ +/* Common code for the plugin and lto1. + Copyright (C) 2008 Free Software Foundation, Inc. + Contributed by Rafael Avila de Espindola (espindola@google.com). + +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 3, 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 COPYING3. If not see +. */ + + + +static const char *lto_resolution_str[9] = +{ + "UNKNOWN", + "UNDEF", + "PREVAILING_DEF", + "PREVAILING_DEF_IRONLY", + "PREEMPTED_REG", + "PREEMPTED_IR", + "RESOLVED_IR", + "RESOLVED_EXEC", + "RESOLVED_DYN" +}; diff --git a/gcc/lto/config-lang.in b/gcc/lto/config-lang.in new file mode 100644 index 00000000000..aa84db1e79f --- /dev/null +++ b/gcc/lto/config-lang.in @@ -0,0 +1,32 @@ +# Top level configure fragment for LTO +# Copyright (C) 2009 +# 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 3, 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 COPYING3. If not see +# . + +language="lto" +compilers="lto1\$(exeext)" +stagestuff="lto1\$(exeext)" + +gtfiles="\$(srcdir)/lto/lto-tree.h \$(srcdir)/lto/lto-lang.c \$(srcdir)/lto/lto.c" + +# LTO is a special front end. From a user's perspective it is not +# really a language, but a middle end feature. However, the GIMPLE +# reading module is implemented as a front end, so enabling LTO means +# enabling this "language". To enable LTO functionality, use +# --enable-lto when configuring the compiler. +build_by_default=no diff --git a/gcc/lto/lang-specs.h b/gcc/lto/lang-specs.h new file mode 100644 index 00000000000..cbcb19b797c --- /dev/null +++ b/gcc/lto/lang-specs.h @@ -0,0 +1,24 @@ +/* LTO driver specs. + Copyright 2009 Free Software Foundation, Inc. + Contributed by CodeSourcery, 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 3, 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 COPYING3. If not see +. */ + +/* LTO contributions to the "compilers" array in gcc.c. */ + + {"@lto", "lto1 %(cc1_options) %i %{!fsyntax-only:%(invoke_as)}", + /*cpp_spec=*/NULL, /*combinable=*/1, /*needs_preprocessing=*/0}, diff --git a/gcc/lto/lang.opt b/gcc/lto/lang.opt new file mode 100644 index 00000000000..f383d7ce18a --- /dev/null +++ b/gcc/lto/lang.opt @@ -0,0 +1,43 @@ +; Options for the LTO front end. +; Copyright (C) 2008 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 3, 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 COPYING3. If not see +; . + +; See the GCC internals manual for a description of this file's format. + +; Please try to keep this file in ASCII collating order. + +Language +LTO + +fltrans +LTO Report Var(flag_ltrans) Optimization +Run the link-time optimizer in local transformation (LTRANS) mode. + +fltrans-output-list= +LTO Joined Var(ltrans_output_list) +Specify a file to which a list of files output by LTRANS is written. + +fwpa +LTO Report Var(flag_wpa) Optimization +Run the link-time optimizer in whole program analysis (WPA) mode. + +resolution +LTO Separate +The resolution file + +; This comment is to ensure we retain the blank line above. diff --git a/gcc/lto/lto-elf.c b/gcc/lto/lto-elf.c new file mode 100644 index 00000000000..ee587f7a750 --- /dev/null +++ b/gcc/lto/lto-elf.c @@ -0,0 +1,729 @@ +/* LTO routines for ELF object files. + Copyright 2009 Free Software Foundation, Inc. + Contributed by CodeSourcery, 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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "toplev.h" +#include +#include "lto.h" +#include "tm.h" +#include "libiberty.h" +#include "ggc.h" +#include "lto-streamer.h" + + +/* Initialize FILE, an LTO file object for FILENAME. */ +static void +lto_file_init (lto_file *file, const char *filename) +{ + file->filename = filename; +} + +/* An ELF file. */ +struct lto_elf_file +{ + /* The base information. */ + lto_file base; + + /* The system file descriptor for the file. */ + int fd; + + /* The libelf descriptor for the file. */ + Elf *elf; + + /* Section number of string table used for section names. */ + size_t sec_strtab; + + /* Writable file members. */ + + /* The currently active section. */ + Elf_Scn *scn; + + /* The output stream for section header names. */ + struct lto_output_stream *shstrtab_stream; + + /* Linked list of data which must be freed *after* the file has been + closed. This is an annoying limitation of libelf. */ + struct lto_char_ptr_base *data; +}; +typedef struct lto_elf_file lto_elf_file; + +/* Stores executable header attributes which must be shared by all ELF files. + This is used for validating input files and populating output files. */ +static struct { + bool initialized; + /* 32 or 64 bits? */ + size_t bits; + unsigned char elf_ident[EI_NIDENT]; + Elf64_Half elf_machine; +} cached_file_attrs; + + +/* Return the section header for SECTION. The return value is never + NULL. Call lto_elf_free_shdr to release the memory allocated. */ + +static Elf64_Shdr * +lto_elf_get_shdr (Elf_Scn *section) +{ + Elf64_Shdr *shdr; + + switch (cached_file_attrs.bits) + { + case 32: + { + Elf32_Shdr *shdr32; + + /* Read the 32-bit section header. */ + shdr32 = elf32_getshdr (section); + if (!shdr32) + fatal_error ("could not read section header: %s", elf_errmsg (0)); + + /* Transform it into a 64-bit section header. */ + shdr = XNEW (Elf64_Shdr); + shdr->sh_name = shdr32->sh_name; + shdr->sh_type = shdr32->sh_type; + shdr->sh_flags = shdr32->sh_flags; + shdr->sh_addr = shdr32->sh_addr; + shdr->sh_offset = shdr32->sh_offset; + shdr->sh_size = shdr32->sh_size; + shdr->sh_link = shdr32->sh_link; + shdr->sh_info = shdr32->sh_info; + shdr->sh_addralign = shdr32->sh_addralign; + shdr->sh_entsize = shdr32->sh_entsize; + break; + } + break; + + case 64: + shdr = elf64_getshdr (section); + if (!shdr) + fatal_error ("could not read section header: %s", elf_errmsg (0)); + break; + + default: + gcc_unreachable (); + } + + return shdr; +} + +/* Free SHDR, previously allocated by lto_elf_get_shdr. */ +static void +lto_elf_free_shdr (Elf64_Shdr *shdr) +{ + if (cached_file_attrs.bits != 64) + free (shdr); +} + + +/* Returns a hash code for P. */ + +static hashval_t +hash_name (const void *p) +{ + const struct lto_section_slot *ds = (const struct lto_section_slot *) p; + return (hashval_t) htab_hash_string (ds->name); +} + + +/* Returns nonzero if P1 and P2 are equal. */ + +static int +eq_name (const void *p1, const void *p2) +{ + const struct lto_section_slot *s1 = + (const struct lto_section_slot *) p1; + const struct lto_section_slot *s2 = + (const struct lto_section_slot *) p2; + + return strcmp (s1->name, s2->name) == 0; +} + + +/* Build a hash table whose key is the section names and whose data is + the start and size of each section in the .o file. */ + +htab_t +lto_elf_build_section_table (lto_file *lto_file) +{ + lto_elf_file *elf_file = (lto_elf_file *)lto_file; + htab_t section_hash_table; + Elf_Scn *section; + size_t base_offset; + + section_hash_table = htab_create (37, hash_name, eq_name, free); + + base_offset = elf_getbase (elf_file->elf); + for (section = elf_getscn (elf_file->elf, 0); + section; + section = elf_nextscn (elf_file->elf, section)) + { + Elf64_Shdr *shdr; + const char *name; + size_t offset; + char *new_name; + void **slot; + struct lto_section_slot s_slot; + + /* Get the name of this section. */ + shdr = lto_elf_get_shdr (section); + offset = shdr->sh_name; + name = elf_strptr (elf_file->elf, + elf_file->sec_strtab, + offset); + + /* Only put lto stuff into the symtab. */ + if (strncmp (name, LTO_SECTION_NAME_PREFIX, + strlen (LTO_SECTION_NAME_PREFIX)) != 0) + { + lto_elf_free_shdr (shdr); + continue; + } + + new_name = XNEWVEC (char, strlen (name) + 1); + strcpy (new_name, name); + s_slot.name = new_name; + slot = htab_find_slot (section_hash_table, &s_slot, INSERT); + if (*slot == NULL) + { + struct lto_section_slot *new_slot = XNEW (struct lto_section_slot); + + new_slot->name = new_name; + /* The offset into the file for this section. */ + new_slot->start = base_offset + shdr->sh_offset; + new_slot->len = shdr->sh_size; + *slot = new_slot; + } + else + { + error ("two or more sections for %s:", new_name); + return NULL; + } + + lto_elf_free_shdr (shdr); + } + + return section_hash_table; +} + + +/* Initialize the section header of section SCN. SH_NAME is the section name + as an index into the section header string table. SH_TYPE is the section + type, an SHT_* macro from libelf headers. */ + +#define DEFINE_INIT_SHDR(BITS) \ +static void \ +init_shdr##BITS (Elf_Scn *scn, size_t sh_name, size_t sh_type) \ +{ \ + Elf##BITS##_Shdr *shdr; \ + \ + shdr = elf##BITS##_getshdr (scn); \ + if (!shdr) \ + { \ + if (BITS == 32) \ + fatal_error ("elf32_getshdr() failed: %s", elf_errmsg (-1)); \ + else \ + fatal_error ("elf64_getshdr() failed: %s", elf_errmsg (-1)); \ + } \ + \ + shdr->sh_name = sh_name; \ + shdr->sh_type = sh_type; \ + shdr->sh_addralign = POINTER_SIZE / BITS_PER_UNIT; \ + shdr->sh_flags = 0; \ + shdr->sh_entsize = 0; \ +} + +DEFINE_INIT_SHDR (32) +DEFINE_INIT_SHDR (64) + +static bool first_data_block; + +/* Begin a new ELF section named NAME with type TYPE in the current output + file. TYPE is an SHT_* macro from the libelf headers. */ + +static void +lto_elf_begin_section_with_type (const char *name, size_t type) +{ + lto_elf_file *file; + Elf_Scn *scn; + size_t sh_name; + + /* Grab the current output file and do some basic assertion checking. */ + file = (lto_elf_file *) lto_get_current_out_file (), + gcc_assert (file); + gcc_assert (file->elf); + gcc_assert (!file->scn); + + /* Create a new section. */ + scn = elf_newscn (file->elf); + if (!scn) + fatal_error ("could not create a new ELF section: %s", elf_errmsg (-1)); + file->scn = scn; + + /* Add a string table entry and record the offset. */ + gcc_assert (file->shstrtab_stream); + sh_name = file->shstrtab_stream->total_size; + lto_output_data_stream (file->shstrtab_stream, name, strlen (name) + 1); + + /* Initialize the section header. */ + switch (cached_file_attrs.bits) + { + case 32: + init_shdr32 (scn, sh_name, type); + break; + + case 64: + init_shdr64 (scn, sh_name, type); + break; + + default: + gcc_unreachable (); + } + + first_data_block = true; +} + + +/* Begin a new ELF section named NAME in the current output file. */ + +void +lto_elf_begin_section (const char *name) +{ + lto_elf_begin_section_with_type (name, SHT_PROGBITS); +} + + +/* Append DATA of length LEN to the current output section. BASE is a pointer + to the output page containing DATA. It is freed once the output file has + been written. */ + +void +lto_elf_append_data (const void *data, size_t len, void *block) +{ + lto_elf_file *file; + Elf_Data *elf_data; + struct lto_char_ptr_base *base = (struct lto_char_ptr_base *) block; + + /* Grab the current output file and do some basic assertion checking. */ + file = (lto_elf_file *) lto_get_current_out_file (); + gcc_assert (file); + gcc_assert (file->scn); + + elf_data = elf_newdata (file->scn); + if (!elf_data) + fatal_error ("could not append data to ELF section: %s", elf_errmsg (-1)); + + if (first_data_block) + { + elf_data->d_align = POINTER_SIZE / BITS_PER_UNIT; + first_data_block = false; + } + else + elf_data->d_align = 1; + elf_data->d_buf = CONST_CAST (void *, data); + elf_data->d_off = 0LL; + elf_data->d_size = len; + elf_data->d_type = ELF_T_BYTE; + elf_data->d_version = EV_CURRENT; + + base->ptr = (char *)file->data; + file->data = base; +} + + +/* End the current output section. This just does some assertion checking + and sets the current output file's scn member to NULL. */ + +void +lto_elf_end_section (void) +{ + lto_elf_file *file; + + /* Grab the current output file and validate some basic assertions. */ + file = (lto_elf_file *) lto_get_current_out_file (); + gcc_assert (file); + gcc_assert (file->scn); + + file->scn = NULL; +} + + +/* Validate's ELF_FILE's executable header and, if cached_file_attrs is + uninitialized, caches the architecture. */ + +#define DEFINE_VALIDATE_EHDR(BITS) \ +static bool \ +validate_ehdr##BITS (lto_elf_file *elf_file) \ +{ \ + Elf##BITS##_Ehdr *elf_header; \ + \ + elf_header = elf##BITS##_getehdr (elf_file->elf); \ + if (!elf_header) \ + { \ + error ("could not read ELF header: %s", elf_errmsg (0)); \ + return false; \ + } \ + \ + if (elf_header->e_type != ET_REL) \ + { \ + error ("not a relocatable ELF object file"); \ + return false; \ + } \ + \ + if (!cached_file_attrs.initialized) \ + cached_file_attrs.elf_machine = elf_header->e_machine; \ + \ + if (cached_file_attrs.elf_machine != elf_header->e_machine) \ + { \ + error ("inconsistent file architecture detected"); \ + return false; \ + } \ + \ + return true; \ +} + +DEFINE_VALIDATE_EHDR (32) +DEFINE_VALIDATE_EHDR (64) + + +/* Validate's ELF_FILE's executable header and, if cached_file_attrs is + uninitialized, caches the results. Also records the section header string + table's section index. Returns true on success or false on failure. */ + +static bool +validate_file (lto_elf_file *elf_file) +{ + const char *elf_ident; + + /* Some aspects of the libelf API are dependent on whether the + object file is a 32-bit or 64-bit file. Determine which kind of + file this is now. */ + elf_ident = elf_getident (elf_file->elf, NULL); + if (!elf_ident) + { + error ("could not read ELF identification information: %s", + elf_errmsg (0)); + return false; + + } + + if (!cached_file_attrs.initialized) + { + switch (elf_ident[EI_CLASS]) + { + case ELFCLASS32: + cached_file_attrs.bits = 32; + break; + + case ELFCLASS64: + cached_file_attrs.bits = 64; + break; + + default: + error ("unsupported ELF file class"); + return false; + } + + memcpy (cached_file_attrs.elf_ident, elf_ident, + sizeof cached_file_attrs.elf_ident); + } + + if (memcmp (elf_ident, cached_file_attrs.elf_ident, + sizeof cached_file_attrs.elf_ident)) + return false; + + /* Check that the input file is a relocatable object file with the correct + architecture. */ + switch (cached_file_attrs.bits) + { + case 32: + if (!validate_ehdr32 (elf_file)) + return false; + break; + + case 64: + if (!validate_ehdr64 (elf_file)) + return false; + break; + + default: + gcc_unreachable (); + } + + /* Read the string table used for section header names. */ + if (elf_getshdrstrndx (elf_file->elf, &elf_file->sec_strtab) == -1) + { + error ("could not locate ELF string table: %s", elf_errmsg (0)); + return false; + } + + cached_file_attrs.initialized = true; + return true; +} + + +/* Helper functions used by init_ehdr. Initialize ELF_FILE's executable + header using cached data from previously read files. */ + +#define DEFINE_INIT_EHDR(BITS) \ +static void \ +init_ehdr##BITS (lto_elf_file *elf_file) \ +{ \ + Elf##BITS##_Ehdr *ehdr; \ + \ + gcc_assert (cached_file_attrs.bits); \ + \ + ehdr = elf##BITS##_newehdr (elf_file->elf); \ + if (!ehdr) \ + { \ + if (BITS == 32) \ + fatal_error ("elf32_newehdr() failed: %s", elf_errmsg (-1)); \ + else \ + fatal_error ("elf64_newehdr() failed: %s", elf_errmsg (-1)); \ + } \ + \ + memcpy (ehdr->e_ident, cached_file_attrs.elf_ident, \ + sizeof cached_file_attrs.elf_ident); \ + ehdr->e_type = ET_REL; \ + ehdr->e_version = EV_CURRENT; \ + ehdr->e_machine = cached_file_attrs.elf_machine; \ +} + +DEFINE_INIT_EHDR (32) +DEFINE_INIT_EHDR (64) + + +/* Initialize ELF_FILE's executable header using cached data from previously + read files. */ + +static void +init_ehdr (lto_elf_file *elf_file) +{ + switch (cached_file_attrs.bits) + { + case 32: + init_ehdr32 (elf_file); + break; + + case 64: + init_ehdr64 (elf_file); + break; + + default: + gcc_unreachable (); + } +} + +/* Open ELF file FILENAME. If WRITABLE is true, the file is opened for write + and, if necessary, created. Otherwise, the file is opened for reading. + Returns the opened file. */ + +lto_file * +lto_elf_file_open (const char *filename, bool writable) +{ + lto_elf_file *elf_file; + lto_file *result; + off_t offset; + const char *offset_p; + char *fname; + + offset_p = strchr (filename, '@'); + if (!offset_p) + { + fname = xstrdup (filename); + offset = 0; + } + else + { + int64_t t; + fname = (char *) xmalloc (offset_p - filename + 1); + memcpy (fname, filename, offset_p - filename); + fname[offset_p - filename] = '\0'; + offset_p++; + sscanf(offset_p, "%" PRId64 , &t); + offset = t; + /* elf_rand expects the offset to point to the ar header, not the + object itself. Subtract the size of the ar header (60 bytes). + We don't uses sizeof (struct ar_hd) to avoid including ar.h */ + offset -= 60; + } + + /* Set up. */ + elf_file = XCNEW (lto_elf_file); + result = (lto_file *) elf_file; + lto_file_init (result, fname); + elf_file->fd = -1; + + /* Open the file. */ + elf_file->fd = open (fname, writable ? O_WRONLY|O_CREAT : O_RDONLY, 0666); + if (elf_file->fd == -1) + { + error ("could not open file %s", fname); + goto fail; + } + + /* Initialize the ELF library. */ + if (elf_version (EV_CURRENT) == EV_NONE) + { + error ("ELF library is older than that used when building GCC"); + goto fail; + } + + /* Open the ELF file descriptor. */ + elf_file->elf = elf_begin (elf_file->fd, writable ? ELF_C_WRITE : ELF_C_READ, + NULL); + if (!elf_file->elf) + { + error ("could not open ELF file: %s", elf_errmsg (0)); + goto fail; + } + + if (offset != 0) + { + Elf *e; + off_t t = elf_rand (elf_file->elf, offset); + if (t != offset) + { + error ("could not seek in archive"); + goto fail; + } + + e = elf_begin (elf_file->fd, ELF_C_READ, elf_file->elf); + if (e == NULL) + { + error("could not find archive member"); + goto fail; + } + elf_end (elf_file->elf); + elf_file->elf = e; + } + + if (writable) + { + init_ehdr (elf_file); + elf_file->shstrtab_stream = XCNEW (struct lto_output_stream); + /* Output an empty string to the section header table. This becomes the + name of the initial NULL section. */ + lto_output_1_stream (elf_file->shstrtab_stream, '\0'); + } + else + if (!validate_file (elf_file)) + goto fail; + + return result; + + fail: + lto_elf_file_close (result); + return NULL; +} + + +/* Close ELF file FILE and clean up any associated data structures. If FILE + was opened for writing, the file's ELF data is written at this time, and + any cached data buffers are freed. */ + +void +lto_elf_file_close (lto_file *file) +{ + lto_elf_file *elf_file = (lto_elf_file *) file; + struct lto_char_ptr_base *cur, *tmp; + + /* Write the ELF section header string table. */ + if (elf_file->shstrtab_stream) + { + size_t strtab; + GElf_Ehdr *ehdr_p, ehdr_buf; + lto_file *old_file = lto_set_current_out_file (file); + + lto_elf_begin_section_with_type (".shstrtab", SHT_STRTAB); + ehdr_p = gelf_getehdr (elf_file->elf, &ehdr_buf); + if (ehdr_p == NULL) + fatal_error ("gelf_getehdr() failed: %s", elf_errmsg (-1)); + strtab = elf_ndxscn (elf_file->scn); + if (strtab < SHN_LORESERVE) + ehdr_p->e_shstrndx = strtab; + else + { + GElf_Shdr *shdr_p, shdr_buf; + Elf_Scn *scn_p = elf_getscn (elf_file->elf, 0); + if (scn_p == NULL) + fatal_error ("elf_getscn() failed: %s", elf_errmsg (-1)); + shdr_p = gelf_getshdr (scn_p, &shdr_buf); + if (shdr_p == NULL) + fatal_error ("gelf_getshdr() failed: %s", elf_errmsg (-1)); + shdr_p->sh_link = strtab; + if (gelf_update_shdr (scn_p, shdr_p) == 0) + fatal_error ("gelf_update_shdr() failed: %s", elf_errmsg (-1)); + ehdr_p->e_shstrndx = SHN_XINDEX; + } + if (gelf_update_ehdr (elf_file->elf, ehdr_p) == 0) + fatal_error ("gelf_update_ehdr() failed: %s", elf_errmsg (-1)); + lto_write_stream (elf_file->shstrtab_stream); + lto_elf_end_section (); + + lto_set_current_out_file (old_file); + free (elf_file->shstrtab_stream); + + if (elf_update (elf_file->elf, ELF_C_WRITE) < 0) + fatal_error ("elf_update() failed: %s", elf_errmsg (-1)); + } + + if (elf_file->elf) + elf_end (elf_file->elf); + if (elf_file->fd != -1) + close (elf_file->fd); + + /* Free any ELF data buffers. */ + cur = elf_file->data; + while (cur) + { + tmp = cur; + cur = (struct lto_char_ptr_base *) cur->ptr; + free (tmp); + } + + free (file); +} + + +/* The current output file. */ +static lto_file *current_out_file; + + +/* Sets the current output file to FILE. Returns the old output file or + NULL. */ + +lto_file * +lto_set_current_out_file (lto_file *file) +{ + lto_file *old_file = current_out_file; + current_out_file = file; + return old_file; +} + + +/* Returns the current output file. */ + +lto_file * +lto_get_current_out_file (void) +{ + return current_out_file; +} diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c new file mode 100644 index 00000000000..04d42307656 --- /dev/null +++ b/gcc/lto/lto-lang.c @@ -0,0 +1,1188 @@ +/* Language-dependent hooks for LTO. + Copyright 2009 Free Software Foundation, Inc. + Contributed by CodeSourcery, 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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "flags.h" +#include "tm.h" +#include "tree.h" +#include "expr.h" +#include "target.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "debug.h" +#include "lto-tree.h" +#include "lto.h" +#include "tree-inline.h" +#include "gimple.h" +#include "toplev.h" + +static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *); +static tree handle_const_attribute (tree *, tree, tree, int, bool *); +static tree handle_malloc_attribute (tree *, tree, tree, int, bool *); +static tree handle_pure_attribute (tree *, tree, tree, int, bool *); +static tree handle_novops_attribute (tree *, tree, tree, int, bool *); +static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); +static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *); +static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_attribute (tree *, tree, tree, int, bool *); +static tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); + +/* Table of machine-independent attributes supported in GIMPLE. */ +const struct attribute_spec lto_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "noreturn", 0, 0, true, false, false, + handle_noreturn_attribute }, + /* The same comments as for noreturn attributes apply to const ones. */ + { "const", 0, 0, true, false, false, + handle_const_attribute }, + { "malloc", 0, 0, true, false, false, + handle_malloc_attribute }, + { "pure", 0, 0, true, false, false, + handle_pure_attribute }, + { "no vops", 0, 0, true, false, false, + handle_novops_attribute }, + { "nonnull", 0, -1, false, true, true, + handle_nonnull_attribute }, + { "nothrow", 0, 0, true, false, false, + handle_nothrow_attribute }, + { "sentinel", 0, 1, false, true, true, + handle_sentinel_attribute }, + { "type generic", 0, 0, false, true, true, + handle_type_generic_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +/* Give the specifications for the format attributes, used by C and all + descendants. */ + +const struct attribute_spec lto_format_attribute_table[] = +{ + /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */ + { "format", 3, 3, false, true, true, + handle_format_attribute }, + { "format_arg", 1, 1, false, true, true, + handle_format_arg_attribute }, + { NULL, 0, 0, false, false, false, NULL } +}; + +enum built_in_attribute +{ +#define DEF_ATTR_NULL_TREE(ENUM) ENUM, +#define DEF_ATTR_INT(ENUM, VALUE) ENUM, +#define DEF_ATTR_IDENT(ENUM, STRING) ENUM, +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM, +#include "builtin-attrs.def" +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST + ATTR_LAST +}; + +static GTY(()) tree built_in_attributes[(int) ATTR_LAST]; + +/* Builtin types. */ + +enum lto_builtin_type +{ +#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME, +#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME, +#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME, +#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, +#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, +#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME, +#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) NAME, +#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7) NAME, +#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME, +#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME, +#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME, +#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME, +#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME, +#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG6) \ + NAME, +#define DEF_POINTER_TYPE(NAME, TYPE) NAME, +#include "builtin-types.def" +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_0 +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_7 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_POINTER_TYPE + BT_LAST +}; + +typedef enum lto_builtin_type builtin_type; + +static GTY(()) tree builtin_types[(int) BT_LAST + 1]; + +static GTY(()) tree string_type_node; +static GTY(()) tree const_string_type_node; +static GTY(()) tree wint_type_node; +static GTY(()) tree intmax_type_node; +static GTY(()) tree uintmax_type_node; +static GTY(()) tree signed_size_type_node; + +/* Flags needed to process builtins.def. */ +int flag_no_builtin; +int flag_no_nonansi_builtin; +int flag_isoc94; +int flag_isoc99; + +/* Attribute handlers. */ + +/* Handle a "noreturn" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree type = TREE_TYPE (*node); + + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_THIS_VOLATILE (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type + (build_type_variant (TREE_TYPE (type), + TYPE_READONLY (TREE_TYPE (type)), 1)); + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "const" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_const_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree type = TREE_TYPE (*node); + + /* See FIXME comment on noreturn in c_common_attribute_table. */ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_READONLY (*node) = 1; + else if (TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE) + TREE_TYPE (*node) + = build_pointer_type + (build_type_variant (TREE_TYPE (type), 1, + TREE_THIS_VOLATILE (TREE_TYPE (type)))); + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "malloc" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_malloc_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL + && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node)))) + DECL_IS_MALLOC (*node) = 1; + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "pure" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_pure_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + DECL_PURE_P (*node) = 1; + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "no vops" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_novops_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *ARG_UNUSED (no_add_attrs)) +{ + gcc_assert (TREE_CODE (*node) == FUNCTION_DECL); + DECL_IS_NOVOPS (*node) = 1; + return NULL_TREE; +} + + +/* Helper for nonnull attribute handling; fetch the operand number + from the attribute argument list. */ + +static bool +get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp) +{ + /* Verify the arg number is a constant. */ + if (TREE_CODE (arg_num_expr) != INTEGER_CST + || TREE_INT_CST_HIGH (arg_num_expr) != 0) + return false; + + *valp = TREE_INT_CST_LOW (arg_num_expr); + return true; +} + +/* Handle the "nonnull" attribute. */ + +static tree +handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name), + tree args, int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree type = *node; + unsigned HOST_WIDE_INT attr_arg_num; + + /* If no arguments are specified, all pointer arguments should be + non-null. Verify a full prototype is given so that the arguments + will have the correct types when we actually check them later. */ + if (!args) + { + gcc_assert (TYPE_ARG_TYPES (type)); + return NULL_TREE; + } + + /* Argument list specified. Verify that each argument number references + a pointer argument. */ + for (attr_arg_num = 1; args; args = TREE_CHAIN (args)) + { + tree argument; + unsigned HOST_WIDE_INT arg_num = 0, ck_num; + + if (!get_nonnull_operand (TREE_VALUE (args), &arg_num)) + gcc_unreachable (); + + argument = TYPE_ARG_TYPES (type); + if (argument) + { + for (ck_num = 1; ; ck_num++) + { + if (!argument || ck_num == arg_num) + break; + argument = TREE_CHAIN (argument); + } + + gcc_assert (argument + && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE); + } + } + + return NULL_TREE; +} + + +/* Handle a "nothrow" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + TREE_NOTHROW (*node) = 1; + else + gcc_unreachable (); + + return NULL_TREE; +} + + +/* Handle a "sentinel" attribute. */ + +static tree +handle_sentinel_attribute (tree *node, tree ARG_UNUSED (name), tree args, + int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree params = TYPE_ARG_TYPES (*node); + gcc_assert (params); + + while (TREE_CHAIN (params)) + params = TREE_CHAIN (params); + + gcc_assert (!VOID_TYPE_P (TREE_VALUE (params))); + + if (args) + { + tree position = TREE_VALUE (args); + gcc_assert (TREE_CODE (position) == INTEGER_CST); + if (tree_int_cst_lt (position, integer_zero_node)) + gcc_unreachable (); + } + + return NULL_TREE; +} + +/* Handle a "type_generic" attribute. */ + +static tree +handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool * ARG_UNUSED (no_add_attrs)) +{ + tree params; + + /* Ensure we have a function type. */ + gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE); + + params = TYPE_ARG_TYPES (*node); + while (params && ! VOID_TYPE_P (TREE_VALUE (params))) + params = TREE_CHAIN (params); + + /* Ensure we have a variadic function. */ + gcc_assert (!params); + + return NULL_TREE; +} + +/* Handle a "format" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_format_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + *no_add_attrs = true; + return NULL_TREE; +} + + +/* Handle a "format_arg" attribute; arguments as in + struct attribute_spec.handler. */ + +tree +handle_format_arg_attribute (tree * ARG_UNUSED (node), tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + *no_add_attrs = true; + return NULL_TREE; +} + + +/* Cribbed from c-common.c. */ + +static void +def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...) +{ + tree args = NULL, t; + va_list list; + int i; + + va_start (list, n); + for (i = 0; i < n; ++i) + { + builtin_type a = (builtin_type) va_arg (list, int); + t = builtin_types[a]; + if (t == error_mark_node) + goto egress; + args = tree_cons (NULL_TREE, t, args); + } + va_end (list); + + args = nreverse (args); + if (!var) + args = chainon (args, void_list_node); + + t = builtin_types[ret]; + if (t == error_mark_node) + goto egress; + t = build_function_type (t, args); + + egress: + builtin_types[def] = t; +} + +/* Used to help initialize the builtin-types.def table. When a type of + the correct size doesn't exist, use error_mark_node instead of NULL. + The later results in segfaults even when a decl using the type doesn't + get invoked. */ + +static tree +builtin_type_for_size (int size, bool unsignedp) +{ + tree type = lang_hooks.types.type_for_size (size, unsignedp); + return type ? type : error_mark_node; +} + +/* Support for DEF_BUILTIN. */ + +static void +def_builtin_1 (enum built_in_function fncode, const char *name, + enum built_in_class fnclass, tree fntype, tree libtype, + bool both_p, bool fallback_p, bool nonansi_p, + tree fnattrs, bool implicit_p) +{ + tree decl; + const char *libname; + + if (fntype == error_mark_node) + return; + + libname = name + strlen ("__builtin_"); + decl = add_builtin_function (name, fntype, fncode, fnclass, + (fallback_p ? libname : NULL), + fnattrs); + + if (both_p + && !flag_no_builtin + && !(nonansi_p && flag_no_nonansi_builtin)) + add_builtin_function (libname, libtype, fncode, fnclass, + NULL, fnattrs); + + built_in_decls[(int) fncode] = decl; + if (implicit_p) + implicit_built_in_decls[(int) fncode] = decl; +} + + +/* Initialize the attribute table for all the supported builtins. */ + +static void +lto_init_attributes (void) +{ + /* Fill in the built_in_attributes array. */ +#define DEF_ATTR_NULL_TREE(ENUM) \ + built_in_attributes[(int) ENUM] = NULL_TREE; +#define DEF_ATTR_INT(ENUM, VALUE) \ + built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE); +#define DEF_ATTR_IDENT(ENUM, STRING) \ + built_in_attributes[(int) ENUM] = get_identifier (STRING); +#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \ + built_in_attributes[(int) ENUM] \ + = tree_cons (built_in_attributes[(int) PURPOSE], \ + built_in_attributes[(int) VALUE], \ + built_in_attributes[(int) CHAIN]); +#include "builtin-attrs.def" +#undef DEF_ATTR_NULL_TREE +#undef DEF_ATTR_INT +#undef DEF_ATTR_IDENT +#undef DEF_ATTR_TREE_LIST +} + +/* Create builtin types and functions. VA_LIST_REF_TYPE_NODE and + VA_LIST_ARG_TYPE_NODE are used in builtin-types.def. */ + +static void +lto_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED, + tree va_list_arg_type_node ATTRIBUTE_UNUSED) +{ +#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \ + builtin_types[ENUM] = VALUE; +#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \ + def_fn_type (ENUM, RETURN, 0, 0); +#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \ + def_fn_type (ENUM, RETURN, 0, 1, ARG1); +#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \ + def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2); +#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3); +#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ + def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4); +#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ + def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6) \ + def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); +#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \ + ARG6, ARG7) \ + def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7); +#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \ + def_fn_type (ENUM, RETURN, 1, 0); +#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \ + def_fn_type (ENUM, RETURN, 1, 1, ARG1); +#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \ + def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2); +#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \ + def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3); +#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \ + def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4); +#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \ + def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5); +#define DEF_POINTER_TYPE(ENUM, TYPE) \ + builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]); + +#include "builtin-types.def" + +#undef DEF_PRIMITIVE_TYPE +#undef DEF_FUNCTION_TYPE_1 +#undef DEF_FUNCTION_TYPE_2 +#undef DEF_FUNCTION_TYPE_3 +#undef DEF_FUNCTION_TYPE_4 +#undef DEF_FUNCTION_TYPE_5 +#undef DEF_FUNCTION_TYPE_6 +#undef DEF_FUNCTION_TYPE_VAR_0 +#undef DEF_FUNCTION_TYPE_VAR_1 +#undef DEF_FUNCTION_TYPE_VAR_2 +#undef DEF_FUNCTION_TYPE_VAR_3 +#undef DEF_FUNCTION_TYPE_VAR_4 +#undef DEF_FUNCTION_TYPE_VAR_5 +#undef DEF_POINTER_TYPE + builtin_types[(int) BT_LAST] = NULL_TREE; + + lto_init_attributes (); + +#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P,\ + NONANSI_P, ATTRS, IMPLICIT, COND) \ + if (NAME && COND) \ + def_builtin_1 (ENUM, NAME, CLASS, builtin_types[(int) TYPE], \ + builtin_types[(int) LIBTYPE], BOTH_P, FALLBACK_P, \ + NONANSI_P, built_in_attributes[(int) ATTRS], IMPLICIT); +#include "builtins.def" +#undef DEF_BUILTIN +} + +static GTY(()) tree registered_builtin_types; + +/* A chain of builtin functions that we need to recognize. We will + assume that all other function names we see will be defined by the + user's program. */ +static GTY(()) tree registered_builtin_fndecls; + +/* Language hooks. */ + +static unsigned int +lto_init_options (unsigned int argc ATTRIBUTE_UNUSED, + const char **argv ATTRIBUTE_UNUSED) +{ + /* Always operate in unit-at-time mode so that we can defer + decisions about what to output. */ + flag_unit_at_a_time = 1; + + return CL_LTO; +} + +/* Handle command-line option SCODE. If the option takes an argument, it is + stored in ARG, which is otherwise NULL. VALUE holds either a numerical + argument or a binary value indicating whether the positive or negative form + of the option was supplied. */ + +const char *resolution_file_name; +static int +lto_handle_option (size_t scode, const char *arg, int value ATTRIBUTE_UNUSED) +{ + enum opt_code code = (enum opt_code) scode; + int result = 1; + + switch (code) + { + case OPT_resolution: + resolution_file_name = arg; + result = 1; + break; + + case OPT_Wabi: + warn_psabi = value; + break; + + default: + break; + } + + return result; +} + +/* Perform post-option processing. Does additional initialization based on + command-line options. PFILENAME is the main input filename. Returns false + to enable subsequent back-end initialization. */ + +static bool +lto_post_options (const char **pfilename ATTRIBUTE_UNUSED) +{ + /* FIXME lto: We have stripped enough type and other + debugging information out of the IR that it may + appear ill-formed to dwarf2out, etc. We must not + attempt to generate debug info in lto1. A more + graceful solution would disable the option flags + rather than ignoring them, but we'd also have to + worry about default debugging options. */ + write_symbols = NO_DEBUG; + debug_info_level = DINFO_LEVEL_NONE; + + /* -fltrans and -fwpa are mutually exclusive. Check for that here. */ + if (flag_wpa && flag_ltrans) + error ("-fwpa and -fltrans are mutually exclusive"); + + if (flag_ltrans) + { + flag_generate_lto = 0; + + /* During LTRANS, we are not looking at the whole program, only + a subset of the whole callgraph. */ + flag_whole_program = 0; + } + + if (flag_wpa) + flag_generate_lto = 1; + + /* Excess precision other than "fast" requires front-end + support. */ + flag_excess_precision_cmdline = EXCESS_PRECISION_FAST; + + lto_read_all_file_options (); + + /* Initialize the compiler back end. */ + return false; +} + +/* Return an integer type with PRECISION bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +static tree +lto_type_for_size (unsigned precision, int unsignedp) +{ + if (precision == TYPE_PRECISION (integer_type_node)) + return unsignedp ? unsigned_type_node : integer_type_node; + + if (precision == TYPE_PRECISION (signed_char_type_node)) + return unsignedp ? unsigned_char_type_node : signed_char_type_node; + + if (precision == TYPE_PRECISION (short_integer_type_node)) + return unsignedp ? short_unsigned_type_node : short_integer_type_node; + + if (precision == TYPE_PRECISION (long_integer_type_node)) + return unsignedp ? long_unsigned_type_node : long_integer_type_node; + + if (precision == TYPE_PRECISION (long_long_integer_type_node)) + return unsignedp + ? long_long_unsigned_type_node + : long_long_integer_type_node; + + if (precision <= TYPE_PRECISION (intQI_type_node)) + return unsignedp ? unsigned_intQI_type_node : intQI_type_node; + + if (precision <= TYPE_PRECISION (intHI_type_node)) + return unsignedp ? unsigned_intHI_type_node : intHI_type_node; + + if (precision <= TYPE_PRECISION (intSI_type_node)) + return unsignedp ? unsigned_intSI_type_node : intSI_type_node; + + if (precision <= TYPE_PRECISION (intDI_type_node)) + return unsignedp ? unsigned_intDI_type_node : intDI_type_node; + + if (precision <= TYPE_PRECISION (intTI_type_node)) + return unsignedp ? unsigned_intTI_type_node : intTI_type_node; + + return NULL_TREE; +} + + +/* Return a data type that has machine mode MODE. + If the mode is an integer, + then UNSIGNEDP selects between signed and unsigned types. + If the mode is a fixed-point mode, + then UNSIGNEDP selects between saturating and nonsaturating types. */ + +static tree +lto_type_for_mode (enum machine_mode mode, int unsigned_p) +{ + tree t; + + if (mode == TYPE_MODE (integer_type_node)) + return unsigned_p ? unsigned_type_node : integer_type_node; + + if (mode == TYPE_MODE (signed_char_type_node)) + return unsigned_p ? unsigned_char_type_node : signed_char_type_node; + + if (mode == TYPE_MODE (short_integer_type_node)) + return unsigned_p ? short_unsigned_type_node : short_integer_type_node; + + if (mode == TYPE_MODE (long_integer_type_node)) + return unsigned_p ? long_unsigned_type_node : long_integer_type_node; + + if (mode == TYPE_MODE (long_long_integer_type_node)) + return unsigned_p ? long_long_unsigned_type_node : long_long_integer_type_node; + + if (mode == QImode) + return unsigned_p ? unsigned_intQI_type_node : intQI_type_node; + + if (mode == HImode) + return unsigned_p ? unsigned_intHI_type_node : intHI_type_node; + + if (mode == SImode) + return unsigned_p ? unsigned_intSI_type_node : intSI_type_node; + + if (mode == DImode) + return unsigned_p ? unsigned_intDI_type_node : intDI_type_node; + +#if HOST_BITS_PER_WIDE_INT >= 64 + if (mode == TYPE_MODE (intTI_type_node)) + return unsigned_p ? 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 (void_type_node)) + return void_type_node; + + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) + return (unsigned_p + ? make_unsigned_type (GET_MODE_PRECISION (mode)) + : make_signed_type (GET_MODE_PRECISION (mode))); + + if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) + return (unsigned_p + ? make_unsigned_type (GET_MODE_PRECISION (mode)) + : make_signed_type (GET_MODE_PRECISION (mode))); + + if (COMPLEX_MODE_P (mode)) + { + enum machine_mode inner_mode; + tree inner_type; + + if (mode == TYPE_MODE (complex_float_type_node)) + return complex_float_type_node; + if (mode == TYPE_MODE (complex_double_type_node)) + return complex_double_type_node; + if (mode == TYPE_MODE (complex_long_double_type_node)) + return complex_long_double_type_node; + + if (mode == TYPE_MODE (complex_integer_type_node) && !unsigned_p) + return complex_integer_type_node; + + inner_mode = GET_MODE_INNER (mode); + inner_type = lto_type_for_mode (inner_mode, unsigned_p); + if (inner_type != NULL_TREE) + return build_complex_type (inner_type); + } + else if (VECTOR_MODE_P (mode)) + { + enum machine_mode inner_mode = GET_MODE_INNER (mode); + tree inner_type = lto_type_for_mode (inner_mode, unsigned_p); + if (inner_type != NULL_TREE) + return build_vector_type_for_mode (inner_type, mode); + } + + if (mode == TYPE_MODE (dfloat32_type_node)) + return dfloat32_type_node; + if (mode == TYPE_MODE (dfloat64_type_node)) + return dfloat64_type_node; + if (mode == TYPE_MODE (dfloat128_type_node)) + return dfloat128_type_node; + + if (ALL_SCALAR_FIXED_POINT_MODE_P (mode)) + { + if (mode == TYPE_MODE (short_fract_type_node)) + return unsigned_p ? sat_short_fract_type_node : short_fract_type_node; + if (mode == TYPE_MODE (fract_type_node)) + return unsigned_p ? sat_fract_type_node : fract_type_node; + if (mode == TYPE_MODE (long_fract_type_node)) + return unsigned_p ? sat_long_fract_type_node : long_fract_type_node; + if (mode == TYPE_MODE (long_long_fract_type_node)) + return unsigned_p ? sat_long_long_fract_type_node + : long_long_fract_type_node; + + if (mode == TYPE_MODE (unsigned_short_fract_type_node)) + return unsigned_p ? sat_unsigned_short_fract_type_node + : unsigned_short_fract_type_node; + if (mode == TYPE_MODE (unsigned_fract_type_node)) + return unsigned_p ? sat_unsigned_fract_type_node + : unsigned_fract_type_node; + if (mode == TYPE_MODE (unsigned_long_fract_type_node)) + return unsigned_p ? sat_unsigned_long_fract_type_node + : unsigned_long_fract_type_node; + if (mode == TYPE_MODE (unsigned_long_long_fract_type_node)) + return unsigned_p ? sat_unsigned_long_long_fract_type_node + : unsigned_long_long_fract_type_node; + + if (mode == TYPE_MODE (short_accum_type_node)) + return unsigned_p ? sat_short_accum_type_node : short_accum_type_node; + if (mode == TYPE_MODE (accum_type_node)) + return unsigned_p ? sat_accum_type_node : accum_type_node; + if (mode == TYPE_MODE (long_accum_type_node)) + return unsigned_p ? sat_long_accum_type_node : long_accum_type_node; + if (mode == TYPE_MODE (long_long_accum_type_node)) + return unsigned_p ? sat_long_long_accum_type_node + : long_long_accum_type_node; + + if (mode == TYPE_MODE (unsigned_short_accum_type_node)) + return unsigned_p ? sat_unsigned_short_accum_type_node + : unsigned_short_accum_type_node; + if (mode == TYPE_MODE (unsigned_accum_type_node)) + return unsigned_p ? sat_unsigned_accum_type_node + : unsigned_accum_type_node; + if (mode == TYPE_MODE (unsigned_long_accum_type_node)) + return unsigned_p ? sat_unsigned_long_accum_type_node + : unsigned_long_accum_type_node; + if (mode == TYPE_MODE (unsigned_long_long_accum_type_node)) + return unsigned_p ? sat_unsigned_long_long_accum_type_node + : unsigned_long_long_accum_type_node; + + if (mode == QQmode) + return unsigned_p ? sat_qq_type_node : qq_type_node; + if (mode == HQmode) + return unsigned_p ? sat_hq_type_node : hq_type_node; + if (mode == SQmode) + return unsigned_p ? sat_sq_type_node : sq_type_node; + if (mode == DQmode) + return unsigned_p ? sat_dq_type_node : dq_type_node; + if (mode == TQmode) + return unsigned_p ? sat_tq_type_node : tq_type_node; + + if (mode == UQQmode) + return unsigned_p ? sat_uqq_type_node : uqq_type_node; + if (mode == UHQmode) + return unsigned_p ? sat_uhq_type_node : uhq_type_node; + if (mode == USQmode) + return unsigned_p ? sat_usq_type_node : usq_type_node; + if (mode == UDQmode) + return unsigned_p ? sat_udq_type_node : udq_type_node; + if (mode == UTQmode) + return unsigned_p ? sat_utq_type_node : utq_type_node; + + if (mode == HAmode) + return unsigned_p ? sat_ha_type_node : ha_type_node; + if (mode == SAmode) + return unsigned_p ? sat_sa_type_node : sa_type_node; + if (mode == DAmode) + return unsigned_p ? sat_da_type_node : da_type_node; + if (mode == TAmode) + return unsigned_p ? sat_ta_type_node : ta_type_node; + + if (mode == UHAmode) + return unsigned_p ? sat_uha_type_node : uha_type_node; + if (mode == USAmode) + return unsigned_p ? sat_usa_type_node : usa_type_node; + if (mode == UDAmode) + return unsigned_p ? sat_uda_type_node : uda_type_node; + if (mode == UTAmode) + return unsigned_p ? sat_uta_type_node : uta_type_node; + } + + for (t = registered_builtin_types; t; t = TREE_CHAIN (t)) + if (TYPE_MODE (TREE_VALUE (t)) == mode) + return TREE_VALUE (t); + + return NULL_TREE; +} + +static int +lto_global_bindings_p (void) +{ + return cfun == NULL; +} + +static void +lto_set_decl_assembler_name (tree decl) +{ + /* This is almost the same as lhd_set_decl_assembler_name, except that + we need to uniquify file-scope names, even if they are not + TREE_PUBLIC, to avoid conflicts between individual files. */ + tree id; + + if (TREE_PUBLIC (decl)) + id = targetm.mangle_decl_assembler_name (decl, DECL_NAME (decl)); + else + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (decl)); + char *label; + + ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl)); + id = get_identifier (label); + } + + SET_DECL_ASSEMBLER_NAME (decl, id); +} + +static tree +lto_pushdecl (tree t ATTRIBUTE_UNUSED) +{ + /* Do nothing, since we get all information from DWARF and LTO + sections. */ + return NULL_TREE; +} + +static tree +lto_getdecls (void) +{ + return registered_builtin_fndecls; +} + +static void +lto_write_globals (void) +{ + tree *vec = VEC_address (tree, lto_global_var_decls); + int len = VEC_length (tree, lto_global_var_decls); + wrapup_global_declarations (vec, len); + emit_debug_global_declarations (vec, len); + VEC_free (tree, gc, lto_global_var_decls); +} + +static tree +lto_builtin_function (tree decl) +{ + /* Record it. */ + TREE_CHAIN (decl) = registered_builtin_fndecls; + registered_builtin_fndecls = decl; + + return decl; +} + +static void +lto_register_builtin_type (tree type, const char *name) +{ + tree decl; + + decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL, get_identifier (name), type); + DECL_ARTIFICIAL (decl) = 1; + if (!TYPE_NAME (type)) + TYPE_NAME (type) = decl; + + registered_builtin_types = tree_cons (0, type, registered_builtin_types); +} + +/* Build nodes that would have be created by the C front-end; necessary + for including builtin-types.def and ultimately builtins.def. */ + +static void +lto_build_c_type_nodes (void) +{ + gcc_assert (void_type_node); + + void_list_node = build_tree_list (NULL_TREE, void_type_node); + string_type_node = build_pointer_type (char_type_node); + const_string_type_node + = build_pointer_type (build_qualified_type (char_type_node, TYPE_QUAL_CONST)); + + if (strcmp (SIZE_TYPE, "unsigned int") == 0) + { + intmax_type_node = integer_type_node; + uintmax_type_node = unsigned_type_node; + signed_size_type_node = integer_type_node; + } + else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) + { + intmax_type_node = long_integer_type_node; + uintmax_type_node = long_unsigned_type_node; + signed_size_type_node = long_integer_type_node; + } + else + gcc_unreachable (); + + wint_type_node = unsigned_type_node; + pid_type_node = integer_type_node; +} + + +/* Perform LTO-specific initialization. */ + +static bool +lto_init (void) +{ + /* We need to generate LTO if running in WPA mode. */ + flag_generate_lto = flag_wpa; + + /* Initialize libcpp line maps for gcc_assert to work. */ + linemap_add (line_table, LC_RENAME, 0, NULL, 0); + linemap_add (line_table, LC_RENAME, 0, NULL, 0); + + /* Create the basic integer types. */ + build_common_tree_nodes (flag_signed_char, /*signed_sizetype=*/false); + + /* Share char_type_node with whatever would be the default for the target. + char_type_node will be used for internal types such as + va_list_type_node but will not be present in the lto stream. */ + char_type_node + = DEFAULT_SIGNED_CHAR ? signed_char_type_node : unsigned_char_type_node; + + /* Tell the middle end what type to use for the size of objects. */ + if (strcmp (SIZE_TYPE, "unsigned int") == 0) + { + set_sizetype (unsigned_type_node); + size_type_node = unsigned_type_node; + } + else if (strcmp (SIZE_TYPE, "long unsigned int") == 0) + { + set_sizetype (long_unsigned_type_node); + size_type_node = long_unsigned_type_node; + } + else + gcc_unreachable (); + + /* The global tree for the main identifier is filled in by + language-specific front-end initialization that is not run in the + LTO back-end. It appears that all languages that perform such + initialization currently do so in the same way, so we do it here. */ + if (main_identifier_node == NULL_TREE) + main_identifier_node = get_identifier ("main"); + + /* In the C++ front-end, fileptr_type_node is defined as a variant + copy of of ptr_type_node, rather than ptr_node itself. The + distinction should only be relevant to the front-end, so we + always use the C definition here in lto1. */ + gcc_assert (fileptr_type_node == ptr_type_node); + + ptrdiff_type_node = integer_type_node; + + /* Create other basic types. */ + build_common_tree_nodes_2 (/*short_double=*/false); + lto_build_c_type_nodes (); + gcc_assert (va_list_type_node); + + if (TREE_CODE (va_list_type_node) == ARRAY_TYPE) + { + tree x = build_pointer_type (TREE_TYPE (va_list_type_node)); + lto_define_builtins (x, x); + } + else + { + lto_define_builtins (va_list_type_node, + build_reference_type (va_list_type_node)); + } + + targetm.init_builtins (); + build_common_builtin_nodes (); + + /* Initialize LTO-specific data structures. */ + lto_global_var_decls = VEC_alloc (tree, gc, 256); + in_lto_p = true; + + return true; +} + +/* Initialize tree structures required by the LTO front end. */ + +static void lto_init_ts (void) +{ + tree_contains_struct[NAMESPACE_DECL][TS_DECL_MINIMAL] = 1; +} + +#undef LANG_HOOKS_NAME +#define LANG_HOOKS_NAME "GNU GIMPLE" +#undef LANG_HOOKS_INIT_OPTIONS +#define LANG_HOOKS_INIT_OPTIONS lto_init_options +#undef LANG_HOOKS_HANDLE_OPTION +#define LANG_HOOKS_HANDLE_OPTION lto_handle_option +#undef LANG_HOOKS_POST_OPTIONS +#define LANG_HOOKS_POST_OPTIONS lto_post_options +#undef LANG_HOOKS_GET_ALIAS_SET +#define LANG_HOOKS_GET_ALIAS_SET gimple_get_alias_set +#undef LANG_HOOKS_TYPE_FOR_MODE +#define LANG_HOOKS_TYPE_FOR_MODE lto_type_for_mode +#undef LANG_HOOKS_TYPE_FOR_SIZE +#define LANG_HOOKS_TYPE_FOR_SIZE lto_type_for_size +#undef LANG_HOOKS_SET_DECL_ASSEMBLER_NAME +#define LANG_HOOKS_SET_DECL_ASSEMBLER_NAME lto_set_decl_assembler_name +#undef LANG_HOOKS_GLOBAL_BINDINGS_P +#define LANG_HOOKS_GLOBAL_BINDINGS_P lto_global_bindings_p +#undef LANG_HOOKS_PUSHDECL +#define LANG_HOOKS_PUSHDECL lto_pushdecl +#undef LANG_HOOKS_GETDECLS +#define LANG_HOOKS_GETDECLS lto_getdecls +#undef LANG_HOOKS_WRITE_GLOBALS +#define LANG_HOOKS_WRITE_GLOBALS lto_write_globals +#undef LANG_HOOKS_REGISTER_BUILTIN_TYPE +#define LANG_HOOKS_REGISTER_BUILTIN_TYPE lto_register_builtin_type +#undef LANG_HOOKS_BUILTIN_FUNCTION +#define LANG_HOOKS_BUILTIN_FUNCTION lto_builtin_function +#undef LANG_HOOKS_INIT +#define LANG_HOOKS_INIT lto_init +#undef LANG_HOOKS_PARSE_FILE +#define LANG_HOOKS_PARSE_FILE lto_main +#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION +#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION tree_rest_of_compilation +#undef LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS +#define LANG_HOOKS_REDUCE_BIT_FIELD_OPERATIONS true +#undef LANG_HOOKS_TYPES_COMPATIBLE_P +#define LANG_HOOKS_TYPES_COMPATIBLE_P NULL + +/* Attribute hooks. */ +#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE +#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE lto_attribute_table +#undef LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE +#define LANG_HOOKS_FORMAT_ATTRIBUTE_TABLE lto_format_attribute_table + +#undef LANG_HOOKS_BEGIN_SECTION +#define LANG_HOOKS_BEGIN_SECTION lto_elf_begin_section +#undef LANG_HOOKS_APPEND_DATA +#define LANG_HOOKS_APPEND_DATA lto_elf_append_data +#undef LANG_HOOKS_END_SECTION +#define LANG_HOOKS_END_SECTION lto_elf_end_section + +#undef LANG_HOOKS_INIT_TS +#define LANG_HOOKS_INIT_TS lto_init_ts + +struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; + +/* Language hooks that are not part of lang_hooks. */ + +tree +convert (tree type ATTRIBUTE_UNUSED, tree expr ATTRIBUTE_UNUSED) +{ + gcc_unreachable (); +} + +/* Tree walking support. */ + +static enum lto_tree_node_structure_enum +lto_tree_node_structure (union lang_tree_node *t ATTRIBUTE_UNUSED) +{ + return TS_LTO_GENERIC; +} + +#include "ggc.h" +#include "gtype-lto.h" +#include "gt-lto-lto-lang.h" diff --git a/gcc/lto/lto-tree.h b/gcc/lto/lto-tree.h new file mode 100644 index 00000000000..671fa4ade26 --- /dev/null +++ b/gcc/lto/lto-tree.h @@ -0,0 +1,61 @@ +/* Language-dependent trees for LTO. + Copyright 2009 Free Software Foundation, Inc. + Contributed by CodeSourcery, 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 3, 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 COPYING3. If not see +. */ + +#ifndef GCC_LTO_TREE_H +#define GCC_LTO_TREE_H + +#include "plugin-api.h" + +struct GTY(()) lang_identifier +{ + struct tree_identifier base; +}; + +struct GTY(()) lang_decl +{ + int dummy; /* Added because ggc does not like empty structs. */ +}; + +struct GTY(()) lang_type +{ + int dummy; /* Added because ggc does not like empty structs. */ +}; + +struct GTY(()) language_function +{ + int dummy; /* Added because ggc does not like empty structs. */ +}; + +enum lto_tree_node_structure_enum { + TS_LTO_GENERIC +}; + +union GTY((desc ("lto_tree_node_structure (&%h)"), + chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)"))) + lang_tree_node +{ + union tree_node GTY ((tag ("TS_LTO_GENERIC"), + desc ("tree_node_structure (&%h)"))) generic; +}; + +/* Vector to keep track of external variables we've seen so far. */ +extern GTY(()) VEC(tree,gc) *lto_global_var_decls; + +#endif /* GCC_LTO_TREE_H */ diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c new file mode 100644 index 00000000000..d8c49cf729f --- /dev/null +++ b/gcc/lto/lto.c @@ -0,0 +1,2021 @@ +/* Top-level LTO routines. + Copyright 2009 Free Software Foundation, Inc. + Contributed by CodeSourcery, 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 3, 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 COPYING3. If not see +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "opts.h" +#include "toplev.h" +#include "tree.h" +#include "diagnostic.h" +#include "tm.h" +#include "libiberty.h" +#include "cgraph.h" +#include "ggc.h" +#include "tree-ssa-operands.h" +#include "tree-pass.h" +#include "langhooks.h" +#include "vec.h" +#include "bitmap.h" +#include "pointer-set.h" +#include "ipa-prop.h" +#include "common.h" +#include "timevar.h" +#include "gimple.h" +#include "lto.h" +#include "lto-tree.h" +#include "lto-streamer.h" + +/* This needs to be included after config.h. Otherwise, _GNU_SOURCE will not + be defined in time to set __USE_GNU in the system headers, and strsignal + will not be declared. */ +#if HAVE_MMAP_FILE +#include +#endif + +DEF_VEC_P(bitmap); +DEF_VEC_ALLOC_P(bitmap,heap); + +/* Read the constructors and inits. */ + +static void +lto_materialize_constructors_and_inits (struct lto_file_decl_data * file_data) +{ + size_t len; + const char *data = lto_get_section_data (file_data, + LTO_section_static_initializer, + NULL, &len); + lto_input_constructors_and_inits (file_data, data); + lto_free_section_data (file_data, LTO_section_static_initializer, NULL, + data, len); +} + +/* Read the function body for the function associated with NODE if possible. */ + +static void +lto_materialize_function (struct cgraph_node *node) +{ + tree decl; + struct lto_file_decl_data *file_data; + const char *data, *name; + size_t len; + tree step; + + /* Ignore clone nodes. Read the body only from the original one. + We may find clone nodes during LTRANS after WPA has made inlining + decisions. */ + if (node->clone_of) + return; + + decl = node->decl; + file_data = node->local.lto_file_data; + name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + + /* We may have renamed the declaration, e.g., a static function. */ + name = lto_get_decl_name_mapping (file_data, name); + + data = lto_get_section_data (file_data, LTO_section_function_body, + name, &len); + if (data) + { + struct function *fn; + + gcc_assert (!DECL_IS_BUILTIN (decl)); + + /* This function has a definition. */ + TREE_STATIC (decl) = 1; + + gcc_assert (DECL_STRUCT_FUNCTION (decl) == NULL); + allocate_struct_function (decl, false); + + /* Load the function body only if not operating in WPA mode. In + WPA mode, the body of the function is not needed. */ + if (!flag_wpa) + { + lto_input_function_body (file_data, decl, data); + lto_stats.num_function_bodies++; + } + + fn = DECL_STRUCT_FUNCTION (decl); + lto_free_section_data (file_data, LTO_section_function_body, name, + data, len); + + /* Look for initializers of constant variables and private + statics. */ + for (step = fn->local_decls; step; step = TREE_CHAIN (step)) + { + tree decl = TREE_VALUE (step); + if (TREE_CODE (decl) == VAR_DECL + && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl)) + && flag_unit_at_a_time) + varpool_finalize_decl (decl); + } + } + else + DECL_EXTERNAL (decl) = 1; + + /* Let the middle end know about the function. */ + rest_of_decl_compilation (decl, 1, 0); + if (cgraph_node (decl)->needed) + cgraph_mark_reachable_node (cgraph_node (decl)); +} + + +/* Decode the content of memory pointed to by DATA in the the + in decl state object STATE. DATA_IN points to a data_in structure for + decoding. Return the address after the decoded object in the input. */ + +static const uint32_t * +lto_read_in_decl_state (struct data_in *data_in, const uint32_t *data, + struct lto_in_decl_state *state) +{ + uint32_t ix; + tree decl; + uint32_t i, j; + + ix = *data++; + decl = lto_streamer_cache_get (data_in->reader_cache, (int) ix); + if (TREE_CODE (decl) != FUNCTION_DECL) + { + gcc_assert (decl == void_type_node); + decl = NULL_TREE; + } + state->fn_decl = decl; + + for (i = 0; i < LTO_N_DECL_STREAMS; i++) + { + uint32_t size = *data++; + tree *decls = (tree *) xcalloc (size, sizeof (tree)); + + for (j = 0; j < size; j++) + { + decls[j] = lto_streamer_cache_get (data_in->reader_cache, data[j]); + + /* Register every type in the global type table. If the + type existed already, use the existing type. */ + if (TYPE_P (decls[j])) + decls[j] = gimple_register_type (decls[j]); + } + + state->streams[i].size = size; + state->streams[i].trees = decls; + data += size; + } + + return data; +} + + +/* Read all the symbols from buffer DATA, using descriptors in DECL_DATA. + RESOLUTIONS is the set of symbols picked by the linker (read from the + resolution file when the linker plugin is being used). */ + +static void +lto_read_decls (struct lto_file_decl_data *decl_data, const void *data, + VEC(ld_plugin_symbol_resolution_t,heap) *resolutions) +{ + const struct lto_decl_header *header = (const struct lto_decl_header *) data; + const int32_t decl_offset = sizeof (struct lto_decl_header); + const int32_t main_offset = decl_offset + header->decl_state_size; + const int32_t string_offset = main_offset + header->main_size; + struct lto_input_block ib_main; + struct data_in *data_in; + unsigned int i; + const uint32_t *data_ptr, *data_end; + uint32_t num_decl_states; + + LTO_INIT_INPUT_BLOCK (ib_main, (const char *) data + main_offset, 0, + header->main_size); + + data_in = lto_data_in_create (decl_data, (const char *) data + string_offset, + header->string_size, resolutions); + + /* Read the global declarations and types. */ + while (ib_main.p < ib_main.len) + { + tree t = lto_input_tree (&ib_main, data_in); + gcc_assert (t && ib_main.p <= ib_main.len); + } + + /* Read in lto_in_decl_state objects. */ + data_ptr = (const uint32_t *) ((const char*) data + decl_offset); + data_end = + (const uint32_t *) ((const char*) data_ptr + header->decl_state_size); + num_decl_states = *data_ptr++; + + gcc_assert (num_decl_states > 0); + decl_data->global_decl_state = lto_new_in_decl_state (); + data_ptr = lto_read_in_decl_state (data_in, data_ptr, + decl_data->global_decl_state); + + /* Read in per-function decl states and enter them in hash table. */ + decl_data->function_decl_states = + htab_create (37, lto_hash_in_decl_state, lto_eq_in_decl_state, free); + + for (i = 1; i < num_decl_states; i++) + { + struct lto_in_decl_state *state = lto_new_in_decl_state (); + void **slot; + + data_ptr = lto_read_in_decl_state (data_in, data_ptr, state); + slot = htab_find_slot (decl_data->function_decl_states, state, INSERT); + gcc_assert (*slot == NULL); + *slot = state; + } + + if (data_ptr != data_end) + internal_error ("bytecode stream: garbage at the end of symbols section"); + + /* Set the current decl state to be the global state. */ + decl_data->current_decl_state = decl_data->global_decl_state; + + lto_data_in_delete (data_in); +} + +/* Read resolution for file named FILE_NAME. The resolution is read from + RESOLUTION. An array with the symbol resolution is returned. The array + size is written to SIZE. */ + +static VEC(ld_plugin_symbol_resolution_t,heap) * +lto_resolution_read (FILE *resolution, const char *file_name) +{ + /* We require that objects in the resolution file are in the same + order as the lto1 command line. */ + unsigned int name_len; + char *obj_name; + unsigned int num_symbols; + unsigned int i; + VEC(ld_plugin_symbol_resolution_t,heap) *ret = NULL; + unsigned max_index = 0; + + if (!resolution) + return NULL; + + name_len = strlen (file_name); + obj_name = XNEWVEC (char, name_len + 1); + fscanf (resolution, " "); /* Read white space. */ + + fread (obj_name, sizeof (char), name_len, resolution); + obj_name[name_len] = '\0'; + if (strcmp (obj_name, file_name) != 0) + internal_error ("unexpected file name %s in linker resolution file. " + "Expected %s", obj_name, file_name); + + free (obj_name); + + fscanf (resolution, "%u", &num_symbols); + + for (i = 0; i < num_symbols; i++) + { + unsigned index; + char r_str[27]; + enum ld_plugin_symbol_resolution r; + unsigned int j; + unsigned int lto_resolution_str_len = + sizeof (lto_resolution_str) / sizeof (char *); + + fscanf (resolution, "%u %26s", &index, r_str); + if (index > max_index) + max_index = index; + + for (j = 0; j < lto_resolution_str_len; j++) + { + if (strcmp (lto_resolution_str[j], r_str) == 0) + { + r = (enum ld_plugin_symbol_resolution) j; + break; + } + } + if (j >= lto_resolution_str_len) + internal_error ("tried to read past the end of the linker resolution " + "file"); + + VEC_safe_grow_cleared (ld_plugin_symbol_resolution_t, heap, ret, + index + 1); + VEC_replace (ld_plugin_symbol_resolution_t, ret, index, r); + } + + return ret; +} + +/* Generate a TREE representation for all types and external decls + entities in FILE. + + Read all of the globals out of the file. Then read the cgraph + and process the .o index into the cgraph nodes so that it can open + the .o file to load the functions and ipa information. */ + +static struct lto_file_decl_data * +lto_file_read (lto_file *file, FILE *resolution_file) +{ + struct lto_file_decl_data *file_data; + const char *data; + size_t len; + VEC(ld_plugin_symbol_resolution_t,heap) *resolutions; + + resolutions = lto_resolution_read (resolution_file, file->filename); + + file_data = XCNEW (struct lto_file_decl_data); + file_data->file_name = file->filename; + file_data->section_hash_table = lto_elf_build_section_table (file); + file_data->renaming_hash_table = lto_create_renaming_table (); + + data = lto_get_section_data (file_data, LTO_section_decls, NULL, &len); + lto_read_decls (file_data, data, resolutions); + lto_free_section_data (file_data, LTO_section_decls, NULL, data, len); + + return file_data; +} + +#if HAVE_MMAP_FILE && HAVE_SYSCONF && defined _SC_PAGE_SIZE +#define LTO_MMAP_IO 1 +#endif + +#if LTO_MMAP_IO +/* Page size of machine is used for mmap and munmap calls. */ +static size_t page_mask; +#endif + +/* Get the section data of length LEN from FILENAME starting at + OFFSET. The data segment must be freed by the caller when the + caller is finished. Returns NULL if all was not well. */ + +static char * +lto_read_section_data (struct lto_file_decl_data *file_data, + intptr_t offset, size_t len) +{ + char *result; + static int fd = -1; + static char *fd_name; +#if LTO_MMAP_IO + intptr_t computed_len; + intptr_t computed_offset; + intptr_t diff; +#endif + + /* Keep a single-entry file-descriptor cache. The last file we + touched will get closed at exit. + ??? Eventually we want to add a more sophisticated larger cache + or rather fix function body streaming to not stream them in + practically random order. */ + if (fd != -1 + && strcmp (fd_name, file_data->file_name) != 0) + { + free (fd_name); + close (fd); + fd = -1; + } + if (fd == -1) + { + fd_name = xstrdup (file_data->file_name); + fd = open (file_data->file_name, O_RDONLY); + if (fd == -1) + return NULL; + } + +#if LTO_MMAP_IO + if (!page_mask) + { + size_t page_size = sysconf (_SC_PAGE_SIZE); + page_mask = ~(page_size - 1); + } + + computed_offset = offset & page_mask; + diff = offset - computed_offset; + computed_len = len + diff; + + result = (char *) mmap (NULL, computed_len, PROT_READ, MAP_PRIVATE, + fd, computed_offset); + if (result == MAP_FAILED) + return NULL; + + return result + diff; +#else + result = (char *) xmalloc (len); + if (lseek (fd, offset, SEEK_SET) != offset + || read (fd, result, len) != (ssize_t) len) + { + free (result); + return NULL; + } + + return result; +#endif +} + + +/* Get the section data from FILE_DATA of SECTION_TYPE with NAME. + NAME will be NULL unless the section type is for a function + body. */ + +static const char * +get_section_data (struct lto_file_decl_data *file_data, + enum lto_section_type section_type, + const char *name, + size_t *len) +{ + htab_t section_hash_table = file_data->section_hash_table; + struct lto_section_slot *f_slot; + struct lto_section_slot s_slot; + const char *section_name = lto_get_section_name (section_type, name); + char *data = NULL; + + *len = 0; + s_slot.name = section_name; + f_slot = (struct lto_section_slot *) htab_find (section_hash_table, &s_slot); + if (f_slot) + { + data = lto_read_section_data (file_data, f_slot->start, f_slot->len); + *len = f_slot->len; + } + + free (CONST_CAST (char *, section_name)); + return data; +} + + +/* Free the section data from FILE_DATA of SECTION_TYPE with NAME that + starts at OFFSET and has LEN bytes. */ + +static void +free_section_data (struct lto_file_decl_data *file_data ATTRIBUTE_UNUSED, + enum lto_section_type section_type ATTRIBUTE_UNUSED, + const char *name ATTRIBUTE_UNUSED, + const char *offset, size_t len ATTRIBUTE_UNUSED) +{ +#if LTO_MMAP_IO + intptr_t computed_len; + intptr_t computed_offset; + intptr_t diff; +#endif + +#if LTO_MMAP_IO + computed_offset = ((intptr_t) offset) & page_mask; + diff = (intptr_t) offset - computed_offset; + computed_len = len + diff; + + munmap ((caddr_t) computed_offset, computed_len); +#else + free (CONST_CAST(char *, offset)); +#endif +} + +/* Vector of all cgraph node sets. */ +static GTY (()) VEC(cgraph_node_set, gc) *lto_cgraph_node_sets; + + +/* Group cgrah nodes by input files. This is used mainly for testing + right now. */ + +static void +lto_1_to_1_map (void) +{ + struct cgraph_node *node; + struct lto_file_decl_data *file_data; + struct pointer_map_t *pmap; + cgraph_node_set set; + void **slot; + + timevar_push (TV_WHOPR_WPA); + + lto_cgraph_node_sets = VEC_alloc (cgraph_node_set, gc, 1); + + /* If the cgraph is empty, create one cgraph node set so that there is still + an output file for any variables that need to be exported in a DSO. */ + if (!cgraph_nodes) + { + set = cgraph_node_set_new (); + VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set); + goto finish; + } + + pmap = pointer_map_create (); + + for (node = cgraph_nodes; node; node = node->next) + { + /* We only need to partition the nodes that we read from the + gimple bytecode files. */ + file_data = node->local.lto_file_data; + if (file_data == NULL) + continue; + + slot = pointer_map_contains (pmap, file_data); + if (slot) + set = (cgraph_node_set) *slot; + else + { + set = cgraph_node_set_new (); + slot = pointer_map_insert (pmap, file_data); + *slot = set; + VEC_safe_push (cgraph_node_set, gc, lto_cgraph_node_sets, set); + } + + cgraph_node_set_add (set, node); + } + + pointer_map_destroy (pmap); + +finish: + timevar_pop (TV_WHOPR_WPA); + + lto_stats.num_cgraph_partitions += VEC_length (cgraph_node_set, + lto_cgraph_node_sets); +} + + +/* Add inlined clone NODE and its master clone to SET, if NODE itself has + inlined callees, recursively add the callees. */ + +static void +lto_add_inline_clones (cgraph_node_set set, struct cgraph_node *node, + bitmap original_decls, bitmap inlined_decls) +{ + struct cgraph_node *callee; + struct cgraph_edge *edge; + + cgraph_node_set_add (set, node); + + if (!bitmap_bit_p (original_decls, DECL_UID (node->decl))) + bitmap_set_bit (inlined_decls, DECL_UID (node->decl)); + + /* Check to see if NODE has any inlined callee. */ + for (edge = node->callees; edge != NULL; edge = edge->next_callee) + { + callee = edge->callee; + if (callee->global.inlined_to != NULL) + lto_add_inline_clones (set, callee, original_decls, inlined_decls); + } +} + +/* Compute the transitive closure of inlining of SET based on the + information in the callgraph. Returns a bitmap of decls that have + been inlined into SET indexed by UID. */ + +static bitmap +lto_add_all_inlinees (cgraph_node_set set) +{ + cgraph_node_set_iterator csi; + struct cgraph_node *node; + bitmap original_nodes = lto_bitmap_alloc (); + bitmap original_decls = lto_bitmap_alloc (); + bitmap inlined_decls = lto_bitmap_alloc (); + bool changed; + + /* We are going to iterate SET while adding to it, mark all original + nodes so that we only add node inlined to original nodes. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + bitmap_set_bit (original_nodes, csi_node (csi)->uid); + bitmap_set_bit (original_decls, DECL_UID (csi_node (csi)->decl)); + } + + /* Some of the original nodes might not be needed anymore. + Remove them. */ + do + { + changed = false; + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + struct cgraph_node *inlined_to; + node = csi_node (csi); + + /* NODE was not inlined. We still need it. */ + if (!node->global.inlined_to) + continue; + + inlined_to = node->global.inlined_to; + + /* NODE should have only one caller. */ + gcc_assert (!node->callers->next_caller); + + if (!bitmap_bit_p (original_nodes, inlined_to->uid)) + { + bitmap_clear_bit (original_nodes, node->uid); + cgraph_node_set_remove (set, node); + changed = true; + } + } + } + while (changed); + + /* Transitively add to SET all the inline clones for every node that + has been inlined. */ + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + { + node = csi_node (csi); + if (bitmap_bit_p (original_nodes, node->uid)) + lto_add_inline_clones (set, node, original_decls, inlined_decls); + } + + lto_bitmap_free (original_nodes); + lto_bitmap_free (original_decls); + + return inlined_decls; +} + +/* Owing to inlining, we may need to promote a file-scope variable + to a global variable. Consider this case: + + a.c: + static int var; + + void + foo (void) + { + var++; + } + + b.c: + + extern void foo (void); + + void + bar (void) + { + foo (); + } + + If WPA inlines FOO inside BAR, then the static variable VAR needs to + be promoted to global because BAR and VAR may be in different LTRANS + files. */ + +/* This struct keeps track of states used in globalization. */ + +typedef struct +{ + /* Current cgraph node set. */ + cgraph_node_set set; + + /* Function DECLs of cgraph nodes seen. */ + bitmap seen_node_decls; + + /* Use in walk_tree to avoid multiple visits of a node. */ + struct pointer_set_t *visited; + + /* static vars in this set. */ + bitmap static_vars_in_set; + + /* static vars in all previous set. */ + bitmap all_static_vars; + + /* all vars in all previous set. */ + bitmap all_vars; +} globalize_context_t; + +/* Callback for walk_tree. Examine the tree pointer to by TP and see if + if its a file-scope static variable of function that need to be turned + into a global. */ + +static tree +globalize_cross_file_statics (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, + void *data) +{ + globalize_context_t *context = (globalize_context_t *) data; + tree t = *tp; + + if (t == NULL_TREE) + return NULL; + + /* The logic for globalization of VAR_DECLs and FUNCTION_DECLs are + different. For functions, we can simply look at the cgraph node sets + to tell if there are references to static functions outside the set. + The cgraph node sets do not keep track of vars, we need to traverse + the trees to determine what vars need to be globalized. */ + if (TREE_CODE (t) == VAR_DECL) + { + if (!TREE_PUBLIC (t)) + { + /* This file-scope static variable is reachable from more + that one set. Make it global but with hidden visibility + so that we do not export it in dynamic linking. */ + if (bitmap_bit_p (context->all_static_vars, DECL_UID (t))) + { + TREE_PUBLIC (t) = 1; + DECL_VISIBILITY (t) = VISIBILITY_HIDDEN; + } + bitmap_set_bit (context->static_vars_in_set, DECL_UID (t)); + } + bitmap_set_bit (context->all_vars, DECL_UID (t)); + walk_tree (&DECL_INITIAL (t), globalize_cross_file_statics, context, + context->visited); + } + else if (TREE_CODE (t) == FUNCTION_DECL && !TREE_PUBLIC (t)) + { + if (!cgraph_node_in_set_p (cgraph_node (t), context->set)) + { + /* This file-scope static function is reachable from a set + which does not contain the function DECL. Make it global + but with hidden visibility. */ + TREE_PUBLIC (t) = 1; + DECL_VISIBILITY (t) = VISIBILITY_HIDDEN; + } + } + + return NULL; +} + +/* Helper of lto_scan_statics_in_cgraph_node below. Scan TABLE for + static decls that may be used in more than one LTRANS file. + CONTEXT is a globalize_context_t for storing scanning states. */ + +static void +lto_scan_statics_in_ref_table (struct lto_tree_ref_table *table, + globalize_context_t *context) +{ + unsigned i; + + for (i = 0; i < table->size; i++) + walk_tree (&table->trees[i], globalize_cross_file_statics, context, + context->visited); +} + +/* Promote file-scope decl reachable from NODE if necessary to global. + CONTEXT is a globalize_context_t storing scanning states. */ + +static void +lto_scan_statics_in_cgraph_node (struct cgraph_node *node, + globalize_context_t *context) +{ + struct lto_in_decl_state *state; + + /* Do nothing if NODE has no function body. */ + if (!node->analyzed) + return; + + /* Return if the DECL of nodes has been visited before. */ + if (bitmap_bit_p (context->seen_node_decls, DECL_UID (node->decl))) + return; + + bitmap_set_bit (context->seen_node_decls, DECL_UID (node->decl)); + + state = lto_get_function_in_decl_state (node->local.lto_file_data, + node->decl); + gcc_assert (state); + + lto_scan_statics_in_ref_table (&state->streams[LTO_DECL_STREAM_VAR_DECL], + context); + lto_scan_statics_in_ref_table (&state->streams[LTO_DECL_STREAM_FN_DECL], + context); +} + +/* Scan all global variables that we have not yet seen so far. CONTEXT + is a globalize_context_t storing scanning states. */ + +static void +lto_scan_statics_in_remaining_global_vars (globalize_context_t *context) +{ + tree var, var_context; + struct varpool_node *vnode; + + FOR_EACH_STATIC_VARIABLE (vnode) + { + var = vnode->decl; + var_context = DECL_CONTEXT (var); + if (TREE_STATIC (var) + && TREE_PUBLIC (var) + && (!var_context || TREE_CODE (var_context) != FUNCTION_DECL) + && !bitmap_bit_p (context->all_vars, DECL_UID (var))) + walk_tree (&var, globalize_cross_file_statics, context, + context->visited); + } +} + +/* Find out all static decls that need to be promoted to global because + of cross file sharing. This function must be run in the WPA mode after + all inlinees are added. */ + +static void +lto_promote_cross_file_statics (void) +{ + unsigned i, n_sets; + cgraph_node_set set; + cgraph_node_set_iterator csi; + globalize_context_t context; + + memset (&context, 0, sizeof (context)); + context.all_vars = lto_bitmap_alloc (); + context.all_static_vars = lto_bitmap_alloc (); + + n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets); + for (i = 0; i < n_sets; i++) + { + set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i); + context.set = set; + context.visited = pointer_set_create (); + context.static_vars_in_set = lto_bitmap_alloc (); + context.seen_node_decls = lto_bitmap_alloc (); + + for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) + lto_scan_statics_in_cgraph_node (csi_node (csi), &context); + + if (i == n_sets - 1) + lto_scan_statics_in_remaining_global_vars (&context); + + bitmap_ior_into (context.all_static_vars, context.static_vars_in_set); + + pointer_set_destroy (context.visited); + lto_bitmap_free (context.static_vars_in_set); + lto_bitmap_free (context.seen_node_decls); + } + + lto_bitmap_free (context.all_vars); + lto_bitmap_free (context.all_static_vars); +} + + +/* Given a file name FNAME, return a string with FNAME prefixed with '*'. */ + +static char * +prefix_name_with_star (const char *fname) +{ + char *star_fname; + size_t len; + + len = strlen (fname) + 1 + 1; + star_fname = XNEWVEC (char, len); + snprintf (star_fname, len, "*%s", fname); + + return star_fname; +} + + +/* Return a copy of FNAME without the .o extension. */ + +static char * +strip_extension (const char *fname) +{ + char *s = XNEWVEC (char, strlen (fname) - 2 + 1); + gcc_assert (strstr (fname, ".o")); + snprintf (s, strlen (fname) - 2 + 1, "%s", fname); + + return s; +} + + +/* Return a file name associated with cgraph node set SET. This may + be a new temporary file name if SET needs to be processed by + LTRANS, or the original file name if all the nodes in SET belong to + the same input file. */ + +static char * +get_filename_for_set (cgraph_node_set set) +{ + char *fname = NULL; + static const size_t max_fname_len = 100; + + if (cgraph_node_set_needs_ltrans_p (set)) + { + /* Create a new temporary file to store SET. To facilitate + debugging, use file names from SET as part of the new + temporary file name. */ + cgraph_node_set_iterator si; + struct pointer_set_t *pset = pointer_set_create (); + for (si = csi_start (set); !csi_end_p (si); csi_next (&si)) + { + struct cgraph_node *n = csi_node (si); + const char *node_fname; + char *f; + + /* Don't use the same file name more than once. */ + if (pointer_set_insert (pset, n->local.lto_file_data)) + continue; + + /* The first file name found in SET determines the output + directory. For the remaining files, we use their + base names. */ + node_fname = n->local.lto_file_data->file_name; + if (fname == NULL) + { + fname = strip_extension (node_fname); + continue; + } + + f = strip_extension (lbasename (node_fname)); + + /* If the new name causes an excessively long file name, + make the last component "___" to indicate overflow. */ + if (strlen (fname) + strlen (f) > max_fname_len - 3) + { + fname = reconcat (fname, fname, "___", NULL); + break; + } + else + { + fname = reconcat (fname, fname, "_", f, NULL); + free (f); + } + } + + pointer_set_destroy (pset); + + /* Add the extension .wpa.o to indicate that this file has been + produced by WPA. */ + fname = reconcat (fname, fname, ".wpa.o", NULL); + gcc_assert (fname); + } + else + { + /* Since SET does not need to be processed by LTRANS, use + the original file name and mark it with a '*' prefix so that + lto_execute_ltrans knows not to process it. */ + cgraph_node_set_iterator si = csi_start (set); + struct cgraph_node *first = csi_node (si); + fname = prefix_name_with_star (first->local.lto_file_data->file_name); + } + + return fname; +} + +static lto_file *current_lto_file; + + +/* Write all output files in WPA mode. Returns a NULL-terminated array of + output file names. */ + +static char ** +lto_wpa_write_files (void) +{ + char **output_files; + unsigned i, n_sets, last_out_file_ix, num_out_files; + lto_file *file; + cgraph_node_set set; + bitmap decls; + VEC(bitmap,heap) *inlined_decls = NULL; + + timevar_push (TV_WHOPR_WPA); + + /* Include all inlined functions and determine what sets need to be + compiled by LTRANS. After this loop, only those sets that + contain callgraph nodes from more than one file will need to be + compiled by LTRANS. */ + for (i = 0; VEC_iterate (cgraph_node_set, lto_cgraph_node_sets, i, set); i++) + { + decls = lto_add_all_inlinees (set); + VEC_safe_push (bitmap, heap, inlined_decls, decls); + lto_stats.num_output_cgraph_nodes += VEC_length (cgraph_node_ptr, + set->nodes); + } + + /* After adding all inlinees, find out statics that need to be promoted + to globals because of cross-file inlining. */ + lto_promote_cross_file_statics (); + + timevar_pop (TV_WHOPR_WPA); + + timevar_push (TV_WHOPR_WPA_IO); + + /* The number of output files depends on the number of input files + and how many callgraph node sets we create. Reserve enough space + for the maximum of these two. */ + num_out_files = MAX (VEC_length (cgraph_node_set, lto_cgraph_node_sets), + num_in_fnames); + output_files = XNEWVEC (char *, num_out_files + 1); + + n_sets = VEC_length (cgraph_node_set, lto_cgraph_node_sets); + for (i = 0; i < n_sets; i++) + { + char *temp_filename; + + set = VEC_index (cgraph_node_set, lto_cgraph_node_sets, i); + temp_filename = get_filename_for_set (set); + output_files[i] = temp_filename; + + if (cgraph_node_set_needs_ltrans_p (set)) + { + /* Write all the nodes in SET to TEMP_FILENAME. */ + file = lto_elf_file_open (temp_filename, true); + if (!file) + fatal_error ("lto_elf_file_open() failed"); + + lto_set_current_out_file (file); + lto_new_extern_inline_states (); + + decls = VEC_index (bitmap, inlined_decls, i); + lto_force_functions_extern_inline (decls); + + ipa_write_summaries_of_cgraph_node_set (set); + lto_delete_extern_inline_states (); + + lto_set_current_out_file (NULL); + lto_elf_file_close (file); + } + } + + last_out_file_ix = n_sets; + + lto_stats.num_output_files += n_sets; + + output_files[last_out_file_ix] = NULL; + + for (i = 0; VEC_iterate (bitmap, inlined_decls, i, decls); i++) + lto_bitmap_free (decls); + VEC_free (bitmap, heap, inlined_decls); + + timevar_pop (TV_WHOPR_WPA_IO); + + return output_files; +} + + +/* Perform local transformations (LTRANS) on the files in the NULL-terminated + FILES array. These should have been written previously by + lto_wpa_write_files (). Transformations are performed via executing + COLLECT_GCC for reach file. */ + +static void +lto_execute_ltrans (char *const *files) +{ + struct pex_obj *pex; + const char *collect_gcc_options, *collect_gcc; + struct obstack env_obstack; + const char **argv; + const char **argv_ptr; + const char *errmsg; + size_t i, j; + int err; + int status; + FILE *ltrans_output_list_stream = NULL; + + timevar_push (TV_WHOPR_WPA_LTRANS_EXEC); + + /* Get the driver and options. */ + collect_gcc = getenv ("COLLECT_GCC"); + if (!collect_gcc) + fatal_error ("environment variable COLLECT_GCC must be set"); + + /* Set the CFLAGS environment variable. */ + collect_gcc_options = getenv ("COLLECT_GCC_OPTIONS"); + if (!collect_gcc_options) + fatal_error ("environment variable COLLECT_GCC_OPTIONS must be set"); + + /* Count arguments. */ + i = 0; + for (j = 0; collect_gcc_options[j] != '\0'; ++j) + if (collect_gcc_options[j] == '\'') + ++i; + + if (i % 2 != 0) + fatal_error ("malformed COLLECT_GCC_OPTIONS"); + + /* Initalize the arguments for the LTRANS driver. */ + argv = XNEWVEC (const char *, 8 + i / 2); + argv_ptr = argv; + *argv_ptr++ = collect_gcc; + *argv_ptr++ = "-xlto"; + for (j = 0; collect_gcc_options[j] != '\0'; ++j) + if (collect_gcc_options[j] == '\'') + { + char *option; + + ++j; + i = j; + while (collect_gcc_options[j] != '\'') + ++j; + obstack_init (&env_obstack); + obstack_grow (&env_obstack, &collect_gcc_options[i], j - i); + obstack_1grow (&env_obstack, 0); + option = XOBFINISH (&env_obstack, char *); + + /* LTRANS does not need -fwpa nor -fltrans-*. */ + if (strncmp (option, "-fwpa", 5) != 0 + && strncmp (option, "-fltrans-", 9) != 0) + *argv_ptr++ = option; + } + *argv_ptr++ = "-fltrans"; + + /* Open the LTRANS output list. */ + if (ltrans_output_list) + { + ltrans_output_list_stream = fopen (ltrans_output_list, "w"); + if (ltrans_output_list_stream == NULL) + error ("opening LTRANS output list %s: %m", ltrans_output_list); + } + + for (i = 0; files[i]; ++i) + { + size_t len; + + /* If the file is prefixed with a '*', it means that we do not + need to re-compile it with LTRANS because it has not been + modified by WPA. Skip it from the command line to + lto_execute_ltrans, but add it to ltrans_output_list_stream + so it is linked after we are done. */ + if (files[i][0] == '*') + { + size_t len = strlen (files[i]) - 1; + if (ltrans_output_list_stream) + if (fwrite (&files[i][1], 1, len, ltrans_output_list_stream) < len + || fwrite ("\n", 1, 1, ltrans_output_list_stream) < 1) + error ("writing to LTRANS output list %s: %m", + ltrans_output_list); + } + else + { + char *output_name; + + /* Otherwise, add FILES[I] to lto_execute_ltrans command line + and add the resulting file to LTRANS output list. */ + + /* Replace the .o suffix with a .ltrans.o suffix and write + the resulting name to the LTRANS output list. */ + obstack_init (&env_obstack); + obstack_grow (&env_obstack, files[i], strlen (files[i]) - 2); + obstack_grow (&env_obstack, ".ltrans.o", sizeof (".ltrans.o")); + output_name = XOBFINISH (&env_obstack, char *); + if (ltrans_output_list_stream) + { + len = strlen (output_name); + + if (fwrite (output_name, 1, len, ltrans_output_list_stream) < len + || fwrite ("\n", 1, 1, ltrans_output_list_stream) < 1) + error ("writing to LTRANS output list %s: %m", + ltrans_output_list); + } + + argv_ptr[0] = "-o"; + argv_ptr[1] = output_name; + argv_ptr[2] = files[i]; + argv_ptr[3] = NULL; + + /* Execute the driver. */ + pex = pex_init (0, "lto1", NULL); + if (pex == NULL) + fatal_error ("pex_init failed: %s", xstrerror (errno)); + + errmsg = pex_run (pex, PEX_LAST | PEX_SEARCH, argv[0], + CONST_CAST (char **, argv), NULL, NULL, &err); + if (errmsg) + fatal_error ("%s: %s", errmsg, xstrerror (err)); + + if (!pex_get_status (pex, 1, &status)) + fatal_error ("can't get program status: %s", xstrerror (errno)); + + if (status) + { + if (WIFSIGNALED (status)) + { + int sig = WTERMSIG (status); + fatal_error ("%s terminated with signal %d [%s]%s", + argv[0], sig, strsignal (sig), + WCOREDUMP (status) ? ", core dumped" : ""); + } + else + fatal_error ("%s terminated with status %d", argv[0], status); + } + + pex_free (pex); + } + } + + /* Close the LTRANS output list. */ + if (ltrans_output_list_stream && fclose (ltrans_output_list_stream)) + error ("closing LTRANS output list %s: %m", ltrans_output_list); + + obstack_free (&env_obstack, NULL); + free (argv); + + timevar_pop (TV_WHOPR_WPA_LTRANS_EXEC); +} + + +typedef struct { + struct pointer_set_t *seen; +} lto_fixup_data_t; + +#define LTO_FIXUP_SUBTREE(t) \ + do \ + walk_tree (&(t), lto_fixup_tree, data, NULL); \ + while (0) + +#define LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE(t) \ + do \ + { \ + if (t) \ + (t) = gimple_register_type (t); \ + walk_tree (&(t), lto_fixup_tree, data, NULL); \ + } \ + while (0) + +static tree lto_fixup_tree (tree *, int *, void *); + +/* Return true if T does not need to be fixed up recursively. */ + +static inline bool +no_fixup_p (tree t) +{ + return (t == NULL + || CONSTANT_CLASS_P (t) + || TREE_CODE (t) == IDENTIFIER_NODE); +} + +/* Fix up fields of a tree_common T. DATA points to fix-up states. */ + +static void +lto_fixup_common (tree t, void *data) +{ + /* The following re-creates the TYPE_REFERENCE_TO and TYPE_POINTER_TO + lists. We do not stream TYPE_REFERENCE_TO, TYPE_POINTER_TO or + TYPE_NEXT_PTR_TO and TYPE_NEXT_REF_TO. + First remove us from any pointer list we are on. */ + if (TREE_CODE (t) == POINTER_TYPE) + { + if (TYPE_POINTER_TO (TREE_TYPE (t)) == t) + TYPE_POINTER_TO (TREE_TYPE (t)) = TYPE_NEXT_PTR_TO (t); + else + { + tree tem = TYPE_POINTER_TO (TREE_TYPE (t)); + while (tem && TYPE_NEXT_PTR_TO (tem) != t) + tem = TYPE_NEXT_PTR_TO (tem); + if (tem) + TYPE_NEXT_PTR_TO (tem) = TYPE_NEXT_PTR_TO (t); + } + TYPE_NEXT_PTR_TO (t) = NULL_TREE; + } + else if (TREE_CODE (t) == REFERENCE_TYPE) + { + if (TYPE_REFERENCE_TO (TREE_TYPE (t)) == t) + TYPE_REFERENCE_TO (TREE_TYPE (t)) = TYPE_NEXT_REF_TO (t); + else + { + tree tem = TYPE_REFERENCE_TO (TREE_TYPE (t)); + while (tem && TYPE_NEXT_REF_TO (tem) != t) + tem = TYPE_NEXT_REF_TO (tem); + if (tem) + TYPE_NEXT_REF_TO (tem) = TYPE_NEXT_REF_TO (t); + } + TYPE_NEXT_REF_TO (t) = NULL_TREE; + } + + /* Fixup our type. */ + LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t)); + + /* Second put us on the list of pointers of the new pointed-to type + if we are a main variant. This is done in lto_fixup_type after + fixing up our main variant. */ + + /* This is not very efficient because we cannot do tail-recursion with + a long chain of trees. */ + LTO_FIXUP_SUBTREE (TREE_CHAIN (t)); +} + +/* Fix up fields of a decl_minimal T. DATA points to fix-up states. */ + +static void +lto_fixup_decl_minimal (tree t, void *data) +{ + lto_fixup_common (t, data); + LTO_FIXUP_SUBTREE (DECL_NAME (t)); + LTO_FIXUP_SUBTREE (DECL_CONTEXT (t)); +} + +/* Fix up fields of a decl_common T. DATA points to fix-up states. */ + +static void +lto_fixup_decl_common (tree t, void *data) +{ + lto_fixup_decl_minimal (t, data); + LTO_FIXUP_SUBTREE (DECL_SIZE (t)); + LTO_FIXUP_SUBTREE (DECL_SIZE_UNIT (t)); + LTO_FIXUP_SUBTREE (DECL_INITIAL (t)); + LTO_FIXUP_SUBTREE (DECL_ATTRIBUTES (t)); + LTO_FIXUP_SUBTREE (DECL_ABSTRACT_ORIGIN (t)); +} + +/* Fix up fields of a decl_with_vis T. DATA points to fix-up states. */ + +static void +lto_fixup_decl_with_vis (tree t, void *data) +{ + lto_fixup_decl_common (t, data); + + /* Accessor macro has side-effects, use field-name here. */ + LTO_FIXUP_SUBTREE (t->decl_with_vis.assembler_name); + + gcc_assert (no_fixup_p (DECL_SECTION_NAME (t))); +} + +/* Fix up fields of a decl_non_common T. DATA points to fix-up states. */ + +static void +lto_fixup_decl_non_common (tree t, void *data) +{ + lto_fixup_decl_with_vis (t, data); + LTO_FIXUP_SUBTREE (DECL_ARGUMENT_FLD (t)); + LTO_FIXUP_SUBTREE (DECL_RESULT_FLD (t)); + LTO_FIXUP_SUBTREE (DECL_VINDEX (t)); + + /* SAVED_TREE should not cleared by now. Also no accessor for base type. */ + gcc_assert (no_fixup_p (t->decl_non_common.saved_tree)); +} + +/* Fix up fields of a decl_non_common T. DATA points to fix-up states. */ + +static void +lto_fixup_function (tree t, void *data) +{ + lto_fixup_decl_non_common (t, data); + LTO_FIXUP_SUBTREE (DECL_FUNCTION_PERSONALITY (t)); +} + +/* Fix up fields of a field_decl T. DATA points to fix-up states. */ + +static void +lto_fixup_field_decl (tree t, void *data) +{ + lto_fixup_decl_common (t, data); + gcc_assert (no_fixup_p (DECL_FIELD_OFFSET (t))); + LTO_FIXUP_SUBTREE (DECL_BIT_FIELD_TYPE (t)); + LTO_FIXUP_SUBTREE (DECL_QUALIFIER (t)); + gcc_assert (no_fixup_p (DECL_FIELD_BIT_OFFSET (t))); + LTO_FIXUP_SUBTREE (DECL_FCONTEXT (t)); +} + +/* Fix up fields of a type T. DATA points to fix-up states. */ + +static void +lto_fixup_type (tree t, void *data) +{ + tree tem, mv; + + lto_fixup_common (t, data); + LTO_FIXUP_SUBTREE (TYPE_CACHED_VALUES (t)); + LTO_FIXUP_SUBTREE (TYPE_SIZE (t)); + LTO_FIXUP_SUBTREE (TYPE_SIZE_UNIT (t)); + LTO_FIXUP_SUBTREE (TYPE_ATTRIBUTES (t)); + LTO_FIXUP_SUBTREE (TYPE_NAME (t)); + + /* Accessors are for derived node types only. */ + if (!POINTER_TYPE_P (t)) + LTO_FIXUP_SUBTREE (t->type.minval); + LTO_FIXUP_SUBTREE (t->type.maxval); + + /* Accessor is for derived node types only. */ + LTO_FIXUP_SUBTREE (t->type.binfo); + + LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CONTEXT (t)); + LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TYPE_CANONICAL (t)); + + /* The following re-creates proper variant lists while fixing up + the variant leaders. We do not stream TYPE_NEXT_VARIANT so the + variant list state before fixup is broken. */ + + /* Remove us from our main variant list if we are not the variant leader. */ + if (TYPE_MAIN_VARIANT (t) != t) + { + tem = TYPE_MAIN_VARIANT (t); + while (tem && TYPE_NEXT_VARIANT (tem) != t) + tem = TYPE_NEXT_VARIANT (tem); + if (tem) + TYPE_NEXT_VARIANT (tem) = TYPE_NEXT_VARIANT (t); + TYPE_NEXT_VARIANT (t) = NULL_TREE; + } + + /* Query our new main variant. */ + mv = gimple_register_type (TYPE_MAIN_VARIANT (t)); + + /* If we were the variant leader and we get replaced ourselves drop + all variants from our list. */ + if (TYPE_MAIN_VARIANT (t) == t + && mv != t) + { + tem = t; + while (tem) + { + tree tem2 = TYPE_NEXT_VARIANT (tem); + TYPE_NEXT_VARIANT (tem) = NULL_TREE; + tem = tem2; + } + } + + /* If we are not our own variant leader link us into our new leaders + variant list. */ + if (mv != t) + { + TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (mv); + TYPE_NEXT_VARIANT (mv) = t; + } + + /* Finally adjust our main variant and fix it up. */ + TYPE_MAIN_VARIANT (t) = mv; + LTO_FIXUP_SUBTREE (TYPE_MAIN_VARIANT (t)); + + /* As the second step of reconstructing the pointer chains put us + on the list of pointers of the new pointed-to type + if we are a main variant. See lto_fixup_common for the first step. */ + if (TREE_CODE (t) == POINTER_TYPE + && TYPE_MAIN_VARIANT (t) == t) + { + TYPE_NEXT_PTR_TO (t) = TYPE_POINTER_TO (TREE_TYPE (t)); + TYPE_POINTER_TO (TREE_TYPE (t)) = t; + } + else if (TREE_CODE (t) == REFERENCE_TYPE + && TYPE_MAIN_VARIANT (t) == t) + { + TYPE_NEXT_REF_TO (t) = TYPE_REFERENCE_TO (TREE_TYPE (t)); + TYPE_REFERENCE_TO (TREE_TYPE (t)) = t; + } +} + +/* Fix up fields of a BINFO T. DATA points to fix-up states. */ + +static void +lto_fixup_binfo (tree t, void *data) +{ + unsigned HOST_WIDE_INT i, n; + tree base, saved_base; + + lto_fixup_common (t, data); + gcc_assert (no_fixup_p (BINFO_OFFSET (t))); + LTO_FIXUP_SUBTREE (BINFO_VTABLE (t)); + LTO_FIXUP_SUBTREE (BINFO_VIRTUALS (t)); + LTO_FIXUP_SUBTREE (BINFO_VPTR_FIELD (t)); + n = VEC_length (tree, BINFO_BASE_ACCESSES (t)); + for (i = 0; i < n; i++) + { + saved_base = base = BINFO_BASE_ACCESS (t, i); + LTO_FIXUP_SUBTREE (base); + if (base != saved_base) + VEC_replace (tree, BINFO_BASE_ACCESSES (t), i, base); + } + LTO_FIXUP_SUBTREE (BINFO_INHERITANCE_CHAIN (t)); + LTO_FIXUP_SUBTREE (BINFO_SUBVTT_INDEX (t)); + LTO_FIXUP_SUBTREE (BINFO_VPTR_INDEX (t)); + n = BINFO_N_BASE_BINFOS (t); + for (i = 0; i < n; i++) + { + saved_base = base = BINFO_BASE_BINFO (t, i); + LTO_FIXUP_SUBTREE (base); + if (base != saved_base) + VEC_replace (tree, BINFO_BASE_BINFOS (t), i, base); + } +} + +/* Fix up fields of a CONSTRUCTOR T. DATA points to fix-up states. */ + +static void +lto_fixup_constructor (tree t, void *data) +{ + unsigned HOST_WIDE_INT idx; + constructor_elt *ce; + + LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t)); + + for (idx = 0; + VEC_iterate(constructor_elt, CONSTRUCTOR_ELTS (t), idx, ce); + idx++) + { + LTO_FIXUP_SUBTREE (ce->index); + LTO_FIXUP_SUBTREE (ce->value); + } +} + +/* A walk_tree callback used by lto_fixup_state. TP is the pointer to the + current tree. WALK_SUBTREES indicates if the subtrees will be walked. + DATA is a pointer set to record visited nodes. */ + +static tree +lto_fixup_tree (tree *tp, int *walk_subtrees, void *data) +{ + tree t; + lto_fixup_data_t *fixup_data = (lto_fixup_data_t *) data; + tree prevailing; + + t = *tp; + *walk_subtrees = 0; + if (pointer_set_contains (fixup_data->seen, t)) + return NULL; + + if (TREE_CODE (t) == VAR_DECL || TREE_CODE (t) == FUNCTION_DECL) + { + prevailing = lto_symtab_prevailing_decl (t); + + if (t != prevailing) + { + if (TREE_CODE (t) == FUNCTION_DECL + && TREE_NOTHROW (prevailing) != TREE_NOTHROW (t)) + { + /* If the prevailing definition does not throw but the + declaration (T) was considered throwing, then we + simply add PREVAILING to the list of throwing + functions. However, if the opposite is true, then + the call to PREVAILING was generated assuming that + the function didn't throw, which means that CFG + cleanup may have removed surrounding try/catch + regions. + + Note that we currently accept these cases even when + they occur within a single file. It's certainly a + user error, but we silently allow the compiler to + remove surrounding try/catch regions. Perhaps we + could emit a warning here, instead of silently + accepting the conflicting declaration. */ + if (TREE_NOTHROW (prevailing)) + lto_mark_nothrow_fndecl (prevailing); + } + + /* Also replace t with prevailing defintion. We don't want to + insert the other defintion in the seen set as we want to + replace all instances of it. */ + *tp = prevailing; + t = prevailing; + } + } + else if (TYPE_P (t)) + { + /* Replace t with the prevailing type. We don't want to insert the + other type in the seen set as we want to replace all instances of it. */ + t = gimple_register_type (t); + *tp = t; + } + + if (pointer_set_insert (fixup_data->seen, t)) + return NULL; + + /* walk_tree does not visit all reachable nodes that need to be fixed up. + Hence we do special processing here for those kind of nodes. */ + switch (TREE_CODE (t)) + { + case FIELD_DECL: + lto_fixup_field_decl (t, data); + break; + + case LABEL_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + case IMPORTED_DECL: + lto_fixup_decl_common (t, data); + break; + + case VAR_DECL: + lto_fixup_decl_with_vis (t, data); + break; + + case TYPE_DECL: + lto_fixup_decl_non_common (t, data); + break; + + case FUNCTION_DECL: + lto_fixup_function (t, data); + break; + + case TREE_BINFO: + lto_fixup_binfo (t, data); + break; + + default: + if (TYPE_P (t)) + lto_fixup_type (t, data); + else if (TREE_CODE (t) == CONSTRUCTOR) + lto_fixup_constructor (t, data); + else if (CONSTANT_CLASS_P (t)) + LTO_REGISTER_TYPE_AND_FIXUP_SUBTREE (TREE_TYPE (t)); + else if (EXPR_P (t)) + { + /* walk_tree only handles TREE_OPERANDs. Do the rest here. */ + lto_fixup_common (t, data); + LTO_FIXUP_SUBTREE (t->exp.block); + *walk_subtrees = 1; + } + else + { + /* Let walk_tree handle sub-trees. */ + *walk_subtrees = 1; + } + } + + return NULL; +} + +/* Helper function of lto_fixup_decls. Walks the var and fn streams in STATE, + replaces var and function decls with the corresponding prevailing def and + records the old decl in the free-list in DATA. We also record visted nodes + in the seen-set in DATA to avoid multiple visit for nodes that need not + to be replaced. */ + +static void +lto_fixup_state (struct lto_in_decl_state *state, lto_fixup_data_t *data) +{ + unsigned i, si; + struct lto_tree_ref_table *table; + + /* Although we only want to replace FUNCTION_DECLs and VAR_DECLs, + we still need to walk from all DECLs to find the reachable + FUNCTION_DECLs and VAR_DECLs. */ + for (si = 0; si < LTO_N_DECL_STREAMS; si++) + { + table = &state->streams[si]; + for (i = 0; i < table->size; i++) + walk_tree (table->trees + i, lto_fixup_tree, data, NULL); + } +} + +/* A callback of htab_traverse. Just extract a state from SLOT and the + lto_fixup_data_t object from AUX and calls lto_fixup_state. */ + +static int +lto_fixup_state_aux (void **slot, void *aux) +{ + struct lto_in_decl_state *state = (struct lto_in_decl_state *) *slot; + lto_fixup_state (state, (lto_fixup_data_t *) aux); + return 1; +} + +/* Fix the decls from all FILES. Replaces each decl with the corresponding + prevailing one. */ + +static void +lto_fixup_decls (struct lto_file_decl_data **files) +{ + unsigned int i; + tree decl; + struct pointer_set_t *seen = pointer_set_create (); + lto_fixup_data_t data; + + data.seen = seen; + for (i = 0; files[i]; i++) + { + struct lto_file_decl_data *file = files[i]; + struct lto_in_decl_state *state = file->global_decl_state; + lto_fixup_state (state, &data); + + htab_traverse (file->function_decl_states, lto_fixup_state_aux, &data); + } + + for (i = 0; VEC_iterate (tree, lto_global_var_decls, i, decl); i++) + { + tree saved_decl = decl; + walk_tree (&decl, lto_fixup_tree, &data, NULL); + if (decl != saved_decl) + VEC_replace (tree, lto_global_var_decls, i, decl); + } + + pointer_set_destroy (seen); +} + +/* Unlink a temporary LTRANS file unless requested otherwise. */ + +static void +lto_maybe_unlink (const char *file) +{ + if (!getenv ("WPA_SAVE_LTRANS")) + { + if (unlink_if_ordinary (file)) + error ("deleting LTRANS input file %s: %m", file); + } + else + fprintf (stderr, "[Leaving LTRANS input file %s]\n", file); +} + +/* Read the options saved from each file in the command line. Called + from lang_hooks.post_options which is called by process_options + right before all the options are used to initialize the compiler. + This assumes that decode_options has already run, so the + num_in_fnames and in_fnames are properly set. + + Note that this assumes that all the files had been compiled with + the same options, which is not a good assumption. In general, + options ought to be read from all the files in the set and merged. + However, it is still unclear what the merge rules should be. */ + +void +lto_read_all_file_options (void) +{ + size_t i; + + /* Clear any file options currently saved. */ + lto_clear_file_options (); + + /* Set the hooks to read ELF sections. */ + lto_set_in_hooks (NULL, get_section_data, free_section_data); + + for (i = 0; i < num_in_fnames; i++) + { + struct lto_file_decl_data *file_data; + lto_file *file = lto_elf_file_open (in_fnames[i], false); + if (!file) + break; + + file_data = XCNEW (struct lto_file_decl_data); + file_data->file_name = file->filename; + file_data->section_hash_table = lto_elf_build_section_table (file); + + lto_read_file_options (file_data); + + lto_elf_file_close (file); + htab_delete (file_data->section_hash_table); + free (file_data); + } + + /* Apply globally the options read from all the files. */ + lto_reissue_options (); +} + + +/* Read all the symbols from the input files FNAMES. NFILES is the + number of files requested in the command line. Instantiate a + global call graph by aggregating all the sub-graphs found in each + file. */ + +static void +read_cgraph_and_symbols (unsigned nfiles, const char **fnames) +{ + unsigned int i, last_file_ix; + struct lto_file_decl_data **all_file_decl_data; + FILE *resolution; + struct cgraph_node *node; + + lto_stats.num_input_files = nfiles; + + timevar_push (TV_IPA_LTO_DECL_IO); + + /* Set the hooks so that all of the ipa passes can read in their data. */ + all_file_decl_data = XNEWVEC (struct lto_file_decl_data *, nfiles + 1); + lto_set_in_hooks (all_file_decl_data, get_section_data, free_section_data); + + /* Read the resolution file. */ + resolution = NULL; + if (resolution_file_name) + { + int t; + unsigned num_objects; + + resolution = fopen (resolution_file_name, "r"); + if (resolution == NULL) + fatal_error ("could not open symbol resolution file: %s", + xstrerror (errno)); + + t = fscanf (resolution, "%u", &num_objects); + gcc_assert (t == 1); + + /* True, since the plugin splits the archives. */ + gcc_assert (num_objects == nfiles); + } + + /* Read all of the object files specified on the command line. */ + for (i = 0, last_file_ix = 0; i < nfiles; ++i) + { + struct lto_file_decl_data *file_data = NULL; + + current_lto_file = lto_elf_file_open (fnames[i], false); + if (!current_lto_file) + break; + + file_data = lto_file_read (current_lto_file, resolution); + if (!file_data) + break; + + all_file_decl_data[last_file_ix++] = file_data; + + lto_elf_file_close (current_lto_file); + current_lto_file = NULL; + } + + if (resolution_file_name) + fclose (resolution); + + all_file_decl_data[last_file_ix] = NULL; + + /* Set the hooks so that all of the ipa passes can read in their data. */ + lto_set_in_hooks (all_file_decl_data, get_section_data, free_section_data); + + /* Each pass will set the appropriate timer. */ + timevar_pop (TV_IPA_LTO_DECL_IO); + + /* Read the callgraph. */ + input_cgraph (); + + /* Merge global decls. */ + lto_symtab_merge_decls (); + + /* Fixup all decls and types and free the type hash tables. */ + lto_fixup_decls (all_file_decl_data); + free_gimple_type_tables (); + + /* Read the IPA summary data. */ + ipa_read_summaries (); + + /* Finally merge the cgraph according to the decl merging decisions. */ + lto_symtab_merge_cgraph_nodes (); + + /* Mark cgraph nodes needed in the merged cgraph + This normally happens in whole-program pass, but for + ltrans the pass was already run at WPA phase. + + FIXME: This is not valid way to do so; nodes can be needed + for non-obvious reasons. We should stream the flags from WPA + phase. */ + if (flag_ltrans) + for (node = cgraph_nodes; node; node = node->next) + if (!node->global.inlined_to + && cgraph_decide_is_function_needed (node, node->decl)) + cgraph_mark_needed_node (node); + + timevar_push (TV_IPA_LTO_DECL_IO); + + /* FIXME lto. This loop needs to be changed to use the pass manager to + call the ipa passes directly. */ + if (!errorcount) + for (i = 0; i < last_file_ix; i++) + { + struct lto_file_decl_data *file_data = all_file_decl_data [i]; + lto_materialize_constructors_and_inits (file_data); + } + + /* Indicate that the cgraph is built and ready. */ + cgraph_function_flags_ready = true; + + timevar_pop (TV_IPA_LTO_DECL_IO); +} + + +/* Materialize all the bodies for all the nodes in the callgraph. */ + +static void +materialize_cgraph (void) +{ + tree decl; + struct cgraph_node *node; + unsigned i; + timevar_id_t lto_timer; + + /* Now that we have input the cgraph, we need to clear all of the aux + nodes and read the functions if we are not running in WPA mode. */ + timevar_push (TV_IPA_LTO_GIMPLE_IO); + + for (node = cgraph_nodes; node; node = node->next) + { + /* Some cgraph nodes get created on the fly, and they don't need + to be materialized. For instance, nodes for nested functions + where the parent function was not streamed out or builtin + functions. Additionally, builtin functions should not be + materialized and may, in fact, cause confusion because there + may be a regular function in the file whose assembler name + matches that of the function. + See gcc.c-torture/execute/20030125-1.c and + gcc.c-torture/execute/921215-1.c. */ + if (node->local.lto_file_data + && !DECL_IS_BUILTIN (node->decl)) + { + lto_materialize_function (node); + lto_stats.num_input_cgraph_nodes++; + } + } + + timevar_pop (TV_IPA_LTO_GIMPLE_IO); + + /* Start the appropriate timer depending on the mode that we are + operating in. */ + lto_timer = (flag_wpa) ? TV_WHOPR_WPA + : (flag_ltrans) ? TV_WHOPR_LTRANS + : TV_LTO; + timevar_push (lto_timer); + + current_function_decl = NULL; + set_cfun (NULL); + + /* Inform the middle end about the global variables we have seen. */ + for (i = 0; VEC_iterate (tree, lto_global_var_decls, i, decl); i++) + rest_of_decl_compilation (decl, 1, 0); + + /* Fix up any calls to DECLs that have become not exception throwing. */ + lto_fixup_nothrow_decls (); + + timevar_pop (lto_timer); +} + + +/* Perform whole program analysis (WPA) on the callgraph and write out the + optimization plan. */ + +static void +do_whole_program_analysis (void) +{ + char **output_files; + size_t i; + struct cgraph_node *node; + + lto_1_to_1_map (); + + /* Note that since we are in WPA mode, materialize_cgraph will not + actually read in all the function bodies. It only materializes + the decls and cgraph nodes so that analysis can be performed. */ + materialize_cgraph (); + + /* Reading in the cgraph uses different timers, start timing WPA now. */ + timevar_push (TV_WHOPR_WPA); + + /* FIXME lto. Hack. We should use the IPA passes. There are a + number of issues with this now. 1. There is no convenient way to + do this. 2. Some passes may depend on properties that requires + the function bodies to compute. */ + cgraph_function_flags_ready = true; + bitmap_obstack_initialize (NULL); + ipa_register_cgraph_hooks (); + + /* Reset inlining information before running IPA inliner. */ + for (node = cgraph_nodes; node; node = node->next) + reset_inline_failed (node); + + /* FIXME lto. We should not call this function directly. */ + pass_ipa_inline.pass.execute (); + + verify_cgraph (); + bitmap_obstack_release (NULL); + + /* We are about to launch the final LTRANS phase, stop the WPA timer. */ + timevar_pop (TV_WHOPR_WPA); + + output_files = lto_wpa_write_files (); + + /* Show the LTO report before launching LTRANS. */ + if (flag_lto_report) + print_lto_report (); + + lto_execute_ltrans (output_files); + + for (i = 0; output_files[i]; ++i) + { + if (output_files[i][0] != '*') + lto_maybe_unlink (output_files[i]); + + free (output_files[i]); + } + + XDELETEVEC (output_files); +} + + +/* Main entry point for the GIMPLE front end. This front end has + three main personalities: + + - LTO (-flto). All the object files on the command line are + loaded in memory and processed as a single translation unit. + This is the traditional link-time optimization behavior. + + - WPA (-fwpa). Only the callgraph and summary information for + files in the command file are loaded. A single callgraph + (without function bodies) is instantiated for the whole set of + files. IPA passes are only allowed to analyze the call graph + and make transformation decisions. The callgraph is + partitioned, each partition is written to a new object file + together with the transformation decisions. + + - LTRANS (-fltrans). Similar to -flto but it prevents the IPA + summary files from running again. Since WPA computed summary + information and decided what transformations to apply, LTRANS + simply applies them. */ + +void +lto_main (int debug_p ATTRIBUTE_UNUSED) +{ + lto_init_reader (); + + /* Read all the symbols and call graph from all the files in the + command line. */ + read_cgraph_and_symbols (num_in_fnames, in_fnames); + + if (!errorcount) + { + /* If WPA is enabled analyze the whole call graph and create an + optimization plan. Otherwise, read in all the function + bodies and continue with optimization. */ + if (flag_wpa) + do_whole_program_analysis (); + else + { + materialize_cgraph (); + + /* Let the middle end know that we have read and merged all of + the input files. */ + cgraph_optimize (); + + /* FIXME lto, if the processes spawned by WPA fail, we miss + the chance to print WPA's report, so WPA will call + print_lto_report before launching LTRANS. If LTRANS was + launched directly by the driver we would not need to do + this. */ + if (flag_lto_report) + print_lto_report (); + } + } +} + +#include "gt-lto-lto.h" diff --git a/gcc/lto/lto.h b/gcc/lto/lto.h new file mode 100644 index 00000000000..cdd1e06de93 --- /dev/null +++ b/gcc/lto/lto.h @@ -0,0 +1,60 @@ +/* LTO declarations. + Copyright 2009 Free Software Foundation, Inc. + Contributed by CodeSourcery, 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 3, 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 COPYING3. If not see +. */ + +#ifndef LTO_H +#define LTO_H + +#include "hashtab.h" + +/* A file. */ +typedef struct lto_file_struct +{ + /* The name of the file. */ + const char *filename; +} lto_file; + +/* In lto-lang.c */ +extern const char *resolution_file_name; + +/* In lto.c */ +extern void lto_main (int); +extern void lto_read_all_file_options (void); + +/* In lto-elf.c */ +extern lto_file *lto_elf_file_open (const char *filename, bool writable); +extern void lto_elf_file_close (lto_file *file); +extern htab_t lto_elf_build_section_table (lto_file *file); +extern void lto_elf_begin_section (const char *name); +extern void lto_elf_append_data (const void *data, size_t len, void *block); +extern void lto_elf_end_section (void); +extern lto_file *lto_set_current_out_file (lto_file *file); +extern lto_file *lto_get_current_out_file (void); + +/* Hash table entry to hold the start offset and length of an LTO + section in a .o file. */ +struct lto_section_slot +{ + const char *name; + intptr_t start; + size_t len; +}; + + +#endif /* LTO_H */ diff --git a/gcc/optabs.c b/gcc/optabs.c index 1c136236060..39257f5a6c3 100644 --- a/gcc/optabs.c +++ b/gcc/optabs.c @@ -1595,11 +1595,11 @@ expand_binop (enum machine_mode mode, optab binoptab, rtx op0, rtx op1, unsigned int bits = GET_MODE_BITSIZE (mode); if (CONST_INT_P (op1)) - newop1 = GEN_INT (bits - INTVAL (op1)); + newop1 = GEN_INT (bits - INTVAL (op1)); else if (targetm.shift_truncation_mask (mode) == bits - 1) - newop1 = negate_rtx (mode, op1); + newop1 = negate_rtx (GET_MODE (op1), op1); else - newop1 = expand_binop (mode, sub_optab, + newop1 = expand_binop (GET_MODE (op1), sub_optab, GEN_INT (bits), op1, NULL_RTX, unsignedp, OPTAB_DIRECT); diff --git a/gcc/optc-gen.awk b/gcc/optc-gen.awk index 2117150f4d1..992e4d316ac 100644 --- a/gcc/optc-gen.awk +++ b/gcc/optc-gen.awk @@ -327,6 +327,7 @@ for (i = 0; i < n_opt_char; i++) { print " " var_opt_char[i] " = ptr->" var_opt_char[i] ";"; } +print " targetm.override_options_after_change ();"; print "}"; print ""; diff --git a/gcc/opts.c b/gcc/opts.c index 0e505181799..878d9587c46 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -44,6 +44,7 @@ along with GCC; see the file COPYING3. If not see #include "debug.h" #include "plugin.h" #include "except.h" +#include "lto-streamer.h" /* Value of the -G xx switch, and whether it was passed or not. */ unsigned HOST_WIDE_INT g_switch_value; @@ -432,6 +433,17 @@ complain_wrong_lang (const char *text, const struct cl_option *option, { char *ok_langs, *bad_lang; + /* The LTO front end inherits all the options from the first front + end that was used. However, not all the original front end + options make sense in LTO. + + A real solution would be to filter this in collect2, but collect2 + does not have access to all the option attributes to know what to + filter. So, in lto1 we silently accept inherited flags and do + nothing about it. */ + if (lang_mask & CL_LTO) + return; + ok_langs = write_langs (option->flags); bad_lang = write_langs (lang_mask); @@ -598,44 +610,31 @@ handle_option (const char **argv, unsigned int lang_mask) } if (option->flag_var) - switch (option->var_type) - { - case CLVC_BOOLEAN: - *(int *) option->flag_var = value; - break; - - case CLVC_EQUAL: - *(int *) option->flag_var = (value - ? option->var_value - : !option->var_value); - break; - - case CLVC_BIT_CLEAR: - case CLVC_BIT_SET: - if ((value != 0) == (option->var_type == CLVC_BIT_SET)) - *(int *) option->flag_var |= option->var_value; - else - *(int *) option->flag_var &= ~option->var_value; - if (option->flag_var == &target_flags) - target_flags_explicit |= option->var_value; - break; - - case CLVC_STRING: - *(const char **) option->flag_var = arg; - break; - } + set_option (option, value, arg); if (option->flags & lang_mask) - if (lang_hooks.handle_option (opt_index, arg, value) == 0) - result = 0; + { + if (lang_hooks.handle_option (opt_index, arg, value) == 0) + result = 0; + else + lto_register_user_option (opt_index, arg, value, lang_mask); + } if (result && (option->flags & CL_COMMON)) - if (common_handle_option (opt_index, arg, value, lang_mask) == 0) - result = 0; + { + if (common_handle_option (opt_index, arg, value, lang_mask) == 0) + result = 0; + else + lto_register_user_option (opt_index, arg, value, CL_COMMON); + } if (result && (option->flags & CL_TARGET)) - if (!targetm.handle_option (opt_index, arg, value)) - result = 0; + { + if (!targetm.handle_option (opt_index, arg, value)) + result = 0; + else + lto_register_user_option (opt_index, arg, value, CL_TARGET); + } done: if (dup) @@ -898,6 +897,7 @@ decode_options (unsigned int argc, const char **argv) flag_tree_pre = opt2; flag_tree_switch_conversion = 1; flag_ipa_cp = opt2; + flag_ipa_sra = opt2; /* Track fields in field-sensitive alias analysis. */ set_param_value ("max-fields-for-field-sensitive", @@ -958,6 +958,9 @@ decode_options (unsigned int argc, const char **argv) flag_unwind_tables = targetm.unwind_tables_default; } + /* Clear any options currently held for LTO. */ + lto_clear_user_options (); + #ifdef OPTIMIZATION_OPTIONS /* Allow default optimizations to be specified on a per-machine basis. */ OPTIMIZATION_OPTIONS (optimize, optimize_size); @@ -1114,6 +1117,28 @@ decode_options (unsigned int argc, const char **argv) PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) = 40; } + if (flag_lto || flag_whopr) + { +#ifdef ENABLE_LTO + flag_generate_lto = 1; + + /* When generating IL, do not operate in whole-program mode. + Otherwise, symbols will be privatized too early, causing link + errors later. */ + flag_whole_program = 0; + + /* FIXME lto. Disable var-tracking until debug information + is properly handled in free_lang_data. */ + flag_var_tracking = 0; +#else + error ("LTO support has not been enabled in this configuration"); +#endif + } + + /* Reconcile -flto and -fwhopr. Set additional flags as appropriate and + check option consistency. */ + if (flag_lto && flag_whopr) + error ("-flto and -fwhopr are mutually exclusive"); } #define LEFT_COLUMN 27 @@ -2099,6 +2124,10 @@ common_handle_option (size_t scode, const char *arg, int value, /* These are no-ops, preserved for backward compatibility. */ break; + case OPT_fuse_linker_plugin: + /* No-op. Used by the driver and passed to us because it starts with f.*/ + break; + default: /* If the flag was handled in a standard way, assume the lack of processing here is intentional. */ @@ -2321,6 +2350,42 @@ get_option_state (int option, struct cl_option_state *state) return true; } +/* Set *OPTION according to VALUE and ARG. */ + +void +set_option (const struct cl_option *option, int value, const char *arg) +{ + if (!option->flag_var) + return; + + switch (option->var_type) + { + case CLVC_BOOLEAN: + *(int *) option->flag_var = value; + break; + + case CLVC_EQUAL: + *(int *) option->flag_var = (value + ? option->var_value + : !option->var_value); + break; + + case CLVC_BIT_CLEAR: + case CLVC_BIT_SET: + if ((value != 0) == (option->var_type == CLVC_BIT_SET)) + *(int *) option->flag_var |= option->var_value; + else + *(int *) option->flag_var &= ~option->var_value; + if (option->flag_var == &target_flags) + target_flags_explicit |= option->var_value; + break; + + case CLVC_STRING: + *(const char **) option->flag_var = arg; + break; + } +} + /* Enable a warning option as an error. This is used by -Werror= and also by legacy Werror-implicit-function-declaration. */ diff --git a/gcc/opts.h b/gcc/opts.h index b4be1111675..a2eef1938c7 100644 --- a/gcc/opts.h +++ b/gcc/opts.h @@ -103,6 +103,7 @@ extern void prune_options (int *argcp, char ***argvp); extern void decode_options (unsigned int argc, const char **argv); extern int option_enabled (int opt_idx); extern bool get_option_state (int, struct cl_option_state *); +extern void set_option (const struct cl_option *, int, const char *); extern void enable_warning_as_error (const char *arg, int value, unsigned int lang_mask); diff --git a/gcc/output.h b/gcc/output.h index 9e2b704920a..5d771d7d06f 100644 --- a/gcc/output.h +++ b/gcc/output.h @@ -626,7 +626,6 @@ extern void default_emit_except_table_label (FILE *); extern void default_internal_label (FILE *, const char *, unsigned long); extern void default_file_start (void); extern void file_end_indicate_exec_stack (void); -extern bool default_valid_pointer_mode (enum machine_mode); extern void default_elf_asm_output_external (FILE *file, tree, const char *); diff --git a/gcc/params.def b/gcc/params.def index 051398573e6..21cfbdc7fec 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -719,6 +719,11 @@ DEFPARAM (PARAM_IRA_MAX_CONFLICT_TABLE_SIZE, "max size of conflict table in MB", 1000, 0, 0) +DEFPARAM (PARAM_IRA_LOOP_RESERVED_REGS, + "ira-loop-reserved-regs", + "The number of registers in each class kept unused by loop invariant motion", + 2, 0, 0) + /* Switch initialization conversion will refuse to create arrays that are bigger than this parameter times the number of switch branches. */ diff --git a/gcc/params.h b/gcc/params.h index 67a7a05c3de..56db145e1f6 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -160,6 +160,8 @@ typedef enum compiler_param PARAM_VALUE (PARAM_IRA_MAX_LOOPS_NUM) #define IRA_MAX_CONFLICT_TABLE_SIZE \ PARAM_VALUE (PARAM_IRA_MAX_CONFLICT_TABLE_SIZE) +#define IRA_LOOP_RESERVED_REGS \ + PARAM_VALUE (PARAM_IRA_LOOP_RESERVED_REGS) #define SWITCH_CONVERSION_BRANCH_RATIO \ PARAM_VALUE (PARAM_SWITCH_CONVERSION_BRANCH_RATIO) #define LOOP_INVARIANT_MAX_BBS_IN_LOOP \ diff --git a/gcc/passes.c b/gcc/passes.c index 5b91698e179..80225490cbd 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-dump.h" #include "df.h" #include "predict.h" +#include "lto-streamer.h" #if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO) #include "dwarf2out.h" @@ -331,7 +332,8 @@ struct rtl_opt_pass pass_postreload = /* The root of the compilation pass tree, once constructed. */ -struct opt_pass *all_passes, *all_ipa_passes, *all_lowering_passes; +struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes, + *all_regular_ipa_passes, *all_lto_gen_passes; /* A map from static pass id to optimization pass. */ struct opt_pass **passes_by_id; @@ -598,22 +600,31 @@ position_pass (struct register_pass_info *new_pass_info, void register_pass (struct register_pass_info *pass_info) { + /* The checks below could fail in buggy plugins. Existing GCC + passes should never fail these checks, so we mention plugin in + the messages. */ if (!pass_info->pass) - { - gcc_unreachable (); - } + fatal_error ("plugin cannot register a missing pass"); + + if (!pass_info->pass->name) + fatal_error ("plugin cannot register an unnamed pass"); if (!pass_info->reference_pass_name) - { - gcc_unreachable (); - } + fatal_error + ("plugin cannot register pass %qs without reference pass name", + pass_info->pass->name); - /* Try to insert the new pass to the pass lists. We need to check all - three lists as the reference pass could be in one (or all) of them. */ + /* Try to insert the new pass to the pass lists. We need to check + all three lists as the reference pass could be in one (or all) of + them. */ if (!position_pass (pass_info, &all_lowering_passes) - && !position_pass (pass_info, &all_ipa_passes) + && !position_pass (pass_info, &all_small_ipa_passes) + && !position_pass (pass_info, &all_regular_ipa_passes) + && !position_pass (pass_info, &all_lto_gen_passes) && !position_pass (pass_info, &all_passes)) - gcc_unreachable (); + fatal_error + ("pass %qs not found but is referenced by new pass %qs", + pass_info->reference_pass_name, pass_info->pass->name); else { /* OK, we have successfully inserted the new pass. We need to register @@ -658,7 +669,7 @@ register_pass (struct register_pass_info *pass_info) If we are optimizing, cgraph_optimize is then invoked: cgraph_optimize () - ipa_passes () -> all_ipa_passes + ipa_passes () -> all_small_ipa_passes cgraph_expand_all_functions () for each node N in the cgraph cgraph_expand_function (N) @@ -679,7 +690,6 @@ init_optimization_passes (void) p = &all_lowering_passes; NEXT_PASS (pass_warn_unused_result); NEXT_PASS (pass_diagnose_omp_blocks); - NEXT_PASS (pass_remove_useless_stmts); NEXT_PASS (pass_mudflap_1); NEXT_PASS (pass_lower_omp); NEXT_PASS (pass_lower_cf); @@ -694,7 +704,7 @@ init_optimization_passes (void) *p = NULL; /* Interprocedural optimization passes. */ - p = &all_ipa_passes; + p = &all_small_ipa_passes; NEXT_PASS (pass_ipa_function_and_variable_visibility); NEXT_PASS (pass_ipa_early_inline); { @@ -716,11 +726,16 @@ init_optimization_passes (void) NEXT_PASS (pass_referenced_vars); NEXT_PASS (pass_build_ssa); NEXT_PASS (pass_early_warn_uninitialized); + /* Note that it is not strictly necessary to schedule an early + inline pass here. However, some test cases (e.g., + g++.dg/other/p334435.C g++.dg/other/i386-1.C) expect extern + inline functions to be inlined even at -O0. This does not + happen during the first early inline pass. */ + NEXT_PASS (pass_rebuild_cgraph_edges); + NEXT_PASS (pass_early_inline); NEXT_PASS (pass_all_early_optimizations); { struct opt_pass **p = &pass_all_early_optimizations.pass.sub; - NEXT_PASS (pass_rebuild_cgraph_edges); - NEXT_PASS (pass_early_inline); NEXT_PASS (pass_remove_cgraph_callee_edges); NEXT_PASS (pass_rename_ssa_copies); NEXT_PASS (pass_ccp); @@ -747,13 +762,23 @@ init_optimization_passes (void) } NEXT_PASS (pass_ipa_increase_alignment); NEXT_PASS (pass_ipa_matrix_reorg); + *p = NULL; + + p = &all_regular_ipa_passes; + NEXT_PASS (pass_ipa_whole_program_visibility); NEXT_PASS (pass_ipa_cp); NEXT_PASS (pass_ipa_inline); NEXT_PASS (pass_ipa_reference); NEXT_PASS (pass_ipa_pure_const); NEXT_PASS (pass_ipa_type_escape); NEXT_PASS (pass_ipa_pta); - NEXT_PASS (pass_ipa_struct_reorg); + NEXT_PASS (pass_ipa_struct_reorg); + *p = NULL; + + p = &all_lto_gen_passes; + NEXT_PASS (pass_ipa_lto_gimple_out); + NEXT_PASS (pass_ipa_lto_wpa_fixup); + NEXT_PASS (pass_ipa_lto_finish_out); /* This must be the last LTO pass. */ *p = NULL; /* These passes are run after IPA passes on every function that is being @@ -855,7 +880,6 @@ init_optimization_passes (void) NEXT_PASS (pass_tree_loop_done); } NEXT_PASS (pass_cse_reciprocals); - NEXT_PASS (pass_convert_to_rsqrt); NEXT_PASS (pass_reassoc); NEXT_PASS (pass_vrp); NEXT_PASS (pass_dominator); @@ -918,6 +942,7 @@ init_optimization_passes (void) NEXT_PASS (pass_rtl_store_motion); NEXT_PASS (pass_cse_after_global_opts); NEXT_PASS (pass_rtl_ifcvt); + NEXT_PASS (pass_reginfo_init); /* Perform loop optimizations. It might be better to do them a bit sooner, but we want the profile feedback to work more efficiently. */ @@ -937,7 +962,6 @@ init_optimization_passes (void) NEXT_PASS (pass_cse2); NEXT_PASS (pass_rtl_dse1); NEXT_PASS (pass_rtl_fwprop_addr); - NEXT_PASS (pass_reginfo_init); NEXT_PASS (pass_inc_dec); NEXT_PASS (pass_initialize_regs); NEXT_PASS (pass_ud_rtl_dce); @@ -953,10 +977,8 @@ init_optimization_passes (void) NEXT_PASS (pass_mode_switching); NEXT_PASS (pass_match_asm_constraints); NEXT_PASS (pass_sms); - NEXT_PASS (pass_subregs_of_mode_init); NEXT_PASS (pass_sched); NEXT_PASS (pass_ira); - NEXT_PASS (pass_subregs_of_mode_finish); NEXT_PASS (pass_postreload); { struct opt_pass **p = &pass_postreload.pass.sub; @@ -1005,7 +1027,13 @@ init_optimization_passes (void) /* Register the passes with the tree dump code. */ register_dump_files (all_lowering_passes, PROP_gimple_any); - register_dump_files (all_ipa_passes, + register_dump_files (all_small_ipa_passes, + PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh + | PROP_cfg); + register_dump_files (all_regular_ipa_passes, + PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh + | PROP_cfg); + register_dump_files (all_lto_gen_passes, PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_cfg); register_dump_files (all_passes, @@ -1032,8 +1060,11 @@ do_per_function (void (*callback) (void *data), void *data) push_cfun (DECL_STRUCT_FUNCTION (node->decl)); current_function_decl = node->decl; callback (data); - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); + if (!flag_wpa) + { + free_dominance_info (CDI_DOMINATORS); + free_dominance_info (CDI_POST_DOMINATORS); + } current_function_decl = NULL; pop_cfun (); ggc_collect (); @@ -1072,7 +1103,7 @@ do_per_function_toporder (void (*callback) (void *data), void *data) /* Allow possibly removed nodes to be garbage collected. */ order[i] = NULL; node->process = 0; - if (node->analyzed && (node->needed || node->reachable)) + if (node->analyzed) { push_cfun (DECL_STRUCT_FUNCTION (node->decl)); current_function_decl = node->decl; @@ -1346,7 +1377,7 @@ add_ipa_transform_pass (void *data) /* Execute summary generation for all of the passes in IPA_PASS. */ -static void +void execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass) { while (ipa_pass) @@ -1355,10 +1386,21 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass) /* Execute all of the IPA_PASSes in the list. */ if (ipa_pass->pass.type == IPA_PASS - && (!pass->gate || pass->gate ())) + && (!pass->gate || pass->gate ()) + && ipa_pass->generate_summary) { pass_init_dump_file (pass); + + /* If a timevar is present, start it. */ + if (pass->tv_id) + timevar_push (pass->tv_id); + ipa_pass->generate_summary (); + + /* Stop timevar. */ + if (pass->tv_id) + timevar_pop (pass->tv_id); + pass_fini_dump_file (pass); } ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->pass.next; @@ -1407,19 +1449,11 @@ execute_one_ipa_transform_pass (struct cgraph_node *node, current_pass = NULL; } -static bool -execute_one_pass (struct opt_pass *pass) -{ - bool initializing_dump; - unsigned int todo_after = 0; - - /* IPA passes are executed on whole program, so cfun should be NULL. - Other passes need function context set. */ - if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) - gcc_assert (!cfun && !current_function_decl); - else - gcc_assert (cfun && current_function_decl); +/* For the current function, execute all ipa transforms. */ +void +execute_all_ipa_transforms (void) +{ if (cfun && cfun->ipa_transforms_to_apply) { unsigned int i; @@ -1428,12 +1462,28 @@ execute_one_pass (struct opt_pass *pass) for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply); i++) execute_one_ipa_transform_pass (node, - VEC_index (ipa_opt_pass, + VEC_index (ipa_opt_pass, cfun->ipa_transforms_to_apply, i)); VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply); cfun->ipa_transforms_to_apply = NULL; } +} + +/* Execute PASS. */ + +static bool +execute_one_pass (struct opt_pass *pass) +{ + bool initializing_dump; + unsigned int todo_after = 0; + + /* IPA passes are executed on whole program, so cfun should be NULL. + Other passes need function context set. */ + if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS) + gcc_assert (!cfun && !current_function_decl); + else + gcc_assert (cfun && current_function_decl); current_pass = pass; @@ -1522,26 +1572,161 @@ execute_pass_list (struct opt_pass *pass) } /* Same as execute_pass_list but assume that subpasses of IPA passes - are local passes. */ + are local passes. If SET is not NULL, write out summaries of only + those node in SET. */ + +static void +ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set, + struct lto_out_decl_state *state) +{ + while (pass) + { + struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *)pass; + gcc_assert (!current_function_decl); + gcc_assert (!cfun); + gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); + if (pass->type == IPA_PASS + && ipa_pass->write_summary + && (!pass->gate || pass->gate ())) + { + /* If a timevar is present, start it. */ + if (pass->tv_id) + timevar_push (pass->tv_id); + + ipa_pass->write_summary (set); + + /* If a timevar is present, start it. */ + if (pass->tv_id) + timevar_pop (pass->tv_id); + } + + if (pass->sub && pass->sub->type != GIMPLE_PASS) + ipa_write_summaries_2 (pass->sub, set, state); + + pass = pass->next; + } +} + +/* Helper function of ipa_write_summaries. Creates and destroys the + decl state and calls ipa_write_summaries_2 for all passes that have + summaries. SET is the set of nodes to be written. */ + +static void +ipa_write_summaries_1 (cgraph_node_set set) +{ + struct lto_out_decl_state *state = lto_new_out_decl_state (); + lto_push_out_decl_state (state); + + if (!flag_wpa) + ipa_write_summaries_2 (all_regular_ipa_passes, set, state); + ipa_write_summaries_2 (all_lto_gen_passes, set, state); + + gcc_assert (lto_get_out_decl_state () == state); + lto_pop_out_decl_state (); + lto_delete_out_decl_state (state); +} + +/* Write out summaries for all the nodes in the callgraph. */ + void -execute_ipa_pass_list (struct opt_pass *pass) +ipa_write_summaries (void) { - bool summaries_generated = false; - do + cgraph_node_set set; + struct cgraph_node **order; + int i, order_pos; + + if (!flag_generate_lto || errorcount || sorrycount) + return; + + lto_new_extern_inline_states (); + set = cgraph_node_set_new (); + + /* Create the callgraph set in the same order used in + cgraph_expand_all_functions. This mostly facilitates debugging, + since it causes the gimple file to be processed in the same order + as the source code. */ + order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes); + order_pos = cgraph_postorder (order); + gcc_assert (order_pos == cgraph_n_nodes); + + for (i = order_pos - 1; i >= 0; i--) + cgraph_node_set_add (set, order[i]); + + ipa_write_summaries_1 (set); + lto_delete_extern_inline_states (); + + free (order); + ggc_free (set); +} + + +/* Write all the summaries for the cgraph nodes in SET. If SET is + NULL, write out all summaries of all nodes. */ + +void +ipa_write_summaries_of_cgraph_node_set (cgraph_node_set set) +{ + if (flag_generate_lto && !(errorcount || sorrycount)) + ipa_write_summaries_1 (set); +} + +/* Same as execute_pass_list but assume that subpasses of IPA passes + are local passes. */ + +static void +ipa_read_summaries_1 (struct opt_pass *pass) +{ + while (pass) { + struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass; + gcc_assert (!current_function_decl); gcc_assert (!cfun); gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); - if (pass->type == IPA_PASS && (!pass->gate || pass->gate ())) + + if (pass->gate == NULL || pass->gate ()) { - if (!summaries_generated) + if (pass->type == IPA_PASS && ipa_pass->read_summary) { - if (!quiet_flag && !cfun) - fprintf (stderr, " "); - execute_ipa_summary_passes ((struct ipa_opt_pass_d *) pass); + /* If a timevar is present, start it. */ + if (pass->tv_id) + timevar_push (pass->tv_id); + + ipa_pass->read_summary (); + + /* Stop timevar. */ + if (pass->tv_id) + timevar_pop (pass->tv_id); } - summaries_generated = true; + + if (pass->sub && pass->sub->type != GIMPLE_PASS) + ipa_read_summaries_1 (pass->sub); } + pass = pass->next; + } +} + + +/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes. */ + +void +ipa_read_summaries (void) +{ + if (!flag_ltrans) + ipa_read_summaries_1 (all_regular_ipa_passes); + ipa_read_summaries_1 (all_lto_gen_passes); +} + +/* Same as execute_pass_list but assume that subpasses of IPA passes + are local passes. */ +void +execute_ipa_pass_list (struct opt_pass *pass) +{ + do + { + gcc_assert (!current_function_decl); + gcc_assert (!cfun); + gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS); if (execute_one_pass (pass) && pass->sub) { if (pass->sub->type == GIMPLE_PASS) @@ -1553,13 +1738,46 @@ execute_ipa_pass_list (struct opt_pass *pass) else gcc_unreachable (); } - if (!current_function_decl) - cgraph_process_new_functions (); + gcc_assert (!current_function_decl); + cgraph_process_new_functions (); pass = pass->next; } while (pass); } +extern void debug_properties (unsigned int); +extern void dump_properties (FILE *, unsigned int); + +void +dump_properties (FILE *dump, unsigned int props) +{ + fprintf (dump, "Properties:\n"); + if (props & PROP_gimple_any) + fprintf (dump, "PROP_gimple_any\n"); + if (props & PROP_gimple_lcf) + fprintf (dump, "PROP_gimple_lcf\n"); + if (props & PROP_gimple_leh) + fprintf (dump, "PROP_gimple_leh\n"); + if (props & PROP_cfg) + fprintf (dump, "PROP_cfg\n"); + if (props & PROP_referenced_vars) + fprintf (dump, "PROP_referenced_vars\n"); + if (props & PROP_ssa) + fprintf (dump, "PROP_ssa\n"); + if (props & PROP_no_crit_edges) + fprintf (dump, "PROP_no_crit_edges\n"); + if (props & PROP_rtl) + fprintf (dump, "PROP_rtl\n"); + if (props & PROP_gimple_lomp) + fprintf (dump, "PROP_gimple_lomp\n"); +} + +void +debug_properties (unsigned int props) +{ + dump_properties (stderr, props); +} + /* Called by local passes to see if function is called by already processed nodes. Because we process nodes in topological order, this means that function is in recursive cycle or we introduced new direct calls. */ @@ -1571,7 +1789,7 @@ function_called_by_processed_nodes_p (void) { if (e->caller->decl == current_function_decl) continue; - if (!e->caller->analyzed || (!e->caller->needed && !e->caller->reachable)) + if (!e->caller->analyzed) continue; if (TREE_ASM_WRITTEN (e->caller->decl)) continue; diff --git a/gcc/plugin.c b/gcc/plugin.c index 414d5783fa5..2d64422787e 100644 --- a/gcc/plugin.c +++ b/gcc/plugin.c @@ -58,7 +58,9 @@ const char *plugin_event_name[] = "PLUGIN_GGC_END", "PLUGIN_REGISTER_GGC_ROOTS", "PLUGIN_REGISTER_GGC_CACHES", - "PLUGIN_START_UNIT", + "PLUGIN_ATTRIBUTES", + "PLUGIN_START_UNIT", + "PLUGIN_PRAGMAS", "PLUGIN_EVENT_LAST" }; @@ -325,6 +327,7 @@ register_callback (const char *plugin_name, case PLUGIN_GGC_MARKING: case PLUGIN_GGC_END: case PLUGIN_ATTRIBUTES: + case PLUGIN_PRAGMAS: case PLUGIN_FINISH: { struct callback_info *new_callback; @@ -344,7 +347,7 @@ register_callback (const char *plugin_name, break; case PLUGIN_EVENT_LAST: default: - error ("Unkown callback event registered by plugin %s", + error ("Unknown callback event registered by plugin %s", plugin_name); } } @@ -368,6 +371,7 @@ invoke_plugin_callbacks (enum plugin_event event, void *gcc_data) case PLUGIN_FINISH_UNIT: case PLUGIN_CXX_CP_PRE_GENERICIZE: case PLUGIN_ATTRIBUTES: + case PLUGIN_PRAGMAS: case PLUGIN_FINISH: case PLUGIN_GGC_START: case PLUGIN_GGC_MARKING: @@ -408,7 +412,7 @@ try_init_one_plugin (struct plugin_name_args *plugin) { void *dl_handle; plugin_init_func plugin_init; - char *err; + const char *err; PTR_UNION_TYPE (plugin_init_func) plugin_init_union; /* We use RTLD_NOW to accelerate binding and detect any mismatch diff --git a/gcc/po/ChangeLog b/gcc/po/ChangeLog index e8ba16b4c8d..e565291c7e1 100644 --- a/gcc/po/ChangeLog +++ b/gcc/po/ChangeLog @@ -1,3 +1,7 @@ +2009-10-17 Joseph Myers + + * gcc.pot: Regenerate. + 2009-09-03 Joseph Myers * fi.po: Update. diff --git a/gcc/po/gcc.pot b/gcc/po/gcc.pot index c3f85328bd8..c00b9d0d016 100644 --- a/gcc/po/gcc.pot +++ b/gcc/po/gcc.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: http://gcc.gnu.org/bugs.html\n" -"POT-Creation-Date: 2009-05-10 10:32+0000\n" +"POT-Creation-Date: 2009-10-17 13:36+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -16,265 +16,265 @@ msgstr "" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" -#: c-decl.c:3944 c-pretty-print.c:393 c-typeck.c:5151 toplev.c:1597 -#: cp/error.c:585 cp/error.c:848 +#: c-decl.c:4539 c-pretty-print.c:393 c-typeck.c:5349 toplev.c:1641 +#: cp/error.c:602 cp/error.c:875 msgid "" msgstr "" -#: c-format.c:361 c-format.c:385 config/i386/msformat-c.c:49 +#: c-format.c:363 c-format.c:387 config/i386/msformat-c.c:49 msgid "' ' flag" msgstr "" -#: c-format.c:361 c-format.c:385 config/i386/msformat-c.c:49 +#: c-format.c:363 c-format.c:387 config/i386/msformat-c.c:49 msgid "the ' ' printf flag" msgstr "" -#: c-format.c:362 c-format.c:386 c-format.c:420 c-format.c:432 c-format.c:491 +#: c-format.c:364 c-format.c:388 c-format.c:422 c-format.c:434 c-format.c:493 #: config/i386/msformat-c.c:50 msgid "'+' flag" msgstr "" -#: c-format.c:362 c-format.c:386 c-format.c:420 c-format.c:432 +#: c-format.c:364 c-format.c:388 c-format.c:422 c-format.c:434 #: config/i386/msformat-c.c:50 msgid "the '+' printf flag" msgstr "" -#: c-format.c:363 c-format.c:387 c-format.c:433 c-format.c:467 +#: c-format.c:365 c-format.c:389 c-format.c:435 c-format.c:469 #: config/i386/msformat-c.c:51 config/i386/msformat-c.c:86 msgid "'#' flag" msgstr "" -#: c-format.c:363 c-format.c:387 c-format.c:433 config/i386/msformat-c.c:51 +#: c-format.c:365 c-format.c:389 c-format.c:435 config/i386/msformat-c.c:51 msgid "the '#' printf flag" msgstr "" -#: c-format.c:364 c-format.c:388 c-format.c:465 config/i386/msformat-c.c:52 +#: c-format.c:366 c-format.c:390 c-format.c:467 config/i386/msformat-c.c:52 msgid "'0' flag" msgstr "" -#: c-format.c:364 c-format.c:388 config/i386/msformat-c.c:52 +#: c-format.c:366 c-format.c:390 config/i386/msformat-c.c:52 msgid "the '0' printf flag" msgstr "" -#: c-format.c:365 c-format.c:389 c-format.c:464 c-format.c:494 +#: c-format.c:367 c-format.c:391 c-format.c:466 c-format.c:496 #: config/i386/msformat-c.c:53 msgid "'-' flag" msgstr "" -#: c-format.c:365 c-format.c:389 config/i386/msformat-c.c:53 +#: c-format.c:367 c-format.c:391 config/i386/msformat-c.c:53 msgid "the '-' printf flag" msgstr "" -#: c-format.c:366 c-format.c:447 config/i386/msformat-c.c:54 +#: c-format.c:368 c-format.c:449 config/i386/msformat-c.c:54 #: config/i386/msformat-c.c:74 msgid "''' flag" msgstr "" -#: c-format.c:366 config/i386/msformat-c.c:54 +#: c-format.c:368 config/i386/msformat-c.c:54 msgid "the ''' printf flag" msgstr "" -#: c-format.c:367 c-format.c:448 +#: c-format.c:369 c-format.c:450 msgid "'I' flag" msgstr "" -#: c-format.c:367 +#: c-format.c:369 msgid "the 'I' printf flag" msgstr "" -#: c-format.c:368 c-format.c:390 c-format.c:445 c-format.c:468 c-format.c:495 -#: c-format.c:1629 config/sol2-c.c:45 config/i386/msformat-c.c:55 +#: c-format.c:370 c-format.c:392 c-format.c:447 c-format.c:470 c-format.c:497 +#: c-format.c:1621 config/sol2-c.c:45 config/i386/msformat-c.c:55 #: config/i386/msformat-c.c:72 msgid "field width" msgstr "" -#: c-format.c:368 c-format.c:390 config/sol2-c.c:45 +#: c-format.c:370 c-format.c:392 config/sol2-c.c:45 #: config/i386/msformat-c.c:55 msgid "field width in printf format" msgstr "" -#: c-format.c:369 c-format.c:391 c-format.c:422 c-format.c:435 +#: c-format.c:371 c-format.c:393 c-format.c:424 c-format.c:437 #: config/i386/msformat-c.c:56 msgid "precision" msgstr "" -#: c-format.c:369 c-format.c:391 c-format.c:422 c-format.c:435 +#: c-format.c:371 c-format.c:393 c-format.c:424 c-format.c:437 #: config/i386/msformat-c.c:56 msgid "precision in printf format" msgstr "" -#: c-format.c:370 c-format.c:392 c-format.c:423 c-format.c:436 c-format.c:446 -#: c-format.c:498 config/sol2-c.c:46 config/i386/msformat-c.c:57 +#: c-format.c:372 c-format.c:394 c-format.c:425 c-format.c:438 c-format.c:448 +#: c-format.c:500 config/sol2-c.c:46 config/i386/msformat-c.c:57 #: config/i386/msformat-c.c:73 msgid "length modifier" msgstr "" -#: c-format.c:370 c-format.c:392 c-format.c:423 c-format.c:436 +#: c-format.c:372 c-format.c:394 c-format.c:425 c-format.c:438 #: config/sol2-c.c:46 config/i386/msformat-c.c:57 msgid "length modifier in printf format" msgstr "" -#: c-format.c:421 c-format.c:434 +#: c-format.c:423 c-format.c:436 msgid "'q' flag" msgstr "" -#: c-format.c:421 c-format.c:434 +#: c-format.c:423 c-format.c:436 msgid "the 'q' diagnostic flag" msgstr "" -#: c-format.c:442 config/i386/msformat-c.c:70 +#: c-format.c:444 config/i386/msformat-c.c:70 msgid "assignment suppression" msgstr "" -#: c-format.c:442 config/i386/msformat-c.c:70 +#: c-format.c:444 config/i386/msformat-c.c:70 msgid "the assignment suppression scanf feature" msgstr "" -#: c-format.c:443 config/i386/msformat-c.c:71 +#: c-format.c:445 config/i386/msformat-c.c:71 msgid "'a' flag" msgstr "" -#: c-format.c:443 config/i386/msformat-c.c:71 +#: c-format.c:445 config/i386/msformat-c.c:71 msgid "the 'a' scanf flag" msgstr "" -#: c-format.c:444 +#: c-format.c:446 msgid "'m' flag" msgstr "" -#: c-format.c:444 +#: c-format.c:446 msgid "the 'm' scanf flag" msgstr "" -#: c-format.c:445 config/i386/msformat-c.c:72 +#: c-format.c:447 config/i386/msformat-c.c:72 msgid "field width in scanf format" msgstr "" -#: c-format.c:446 config/i386/msformat-c.c:73 +#: c-format.c:448 config/i386/msformat-c.c:73 msgid "length modifier in scanf format" msgstr "" -#: c-format.c:447 config/i386/msformat-c.c:74 +#: c-format.c:449 config/i386/msformat-c.c:74 msgid "the ''' scanf flag" msgstr "" -#: c-format.c:448 +#: c-format.c:450 msgid "the 'I' scanf flag" msgstr "" -#: c-format.c:463 +#: c-format.c:465 msgid "'_' flag" msgstr "" -#: c-format.c:463 +#: c-format.c:465 msgid "the '_' strftime flag" msgstr "" -#: c-format.c:464 +#: c-format.c:466 msgid "the '-' strftime flag" msgstr "" -#: c-format.c:465 +#: c-format.c:467 msgid "the '0' strftime flag" msgstr "" -#: c-format.c:466 c-format.c:490 +#: c-format.c:468 c-format.c:492 msgid "'^' flag" msgstr "" -#: c-format.c:466 +#: c-format.c:468 msgid "the '^' strftime flag" msgstr "" -#: c-format.c:467 config/i386/msformat-c.c:86 +#: c-format.c:469 config/i386/msformat-c.c:86 msgid "the '#' strftime flag" msgstr "" -#: c-format.c:468 +#: c-format.c:470 msgid "field width in strftime format" msgstr "" -#: c-format.c:469 +#: c-format.c:471 msgid "'E' modifier" msgstr "" -#: c-format.c:469 +#: c-format.c:471 msgid "the 'E' strftime modifier" msgstr "" -#: c-format.c:470 +#: c-format.c:472 msgid "'O' modifier" msgstr "" -#: c-format.c:470 +#: c-format.c:472 msgid "the 'O' strftime modifier" msgstr "" -#: c-format.c:471 +#: c-format.c:473 msgid "the 'O' modifier" msgstr "" -#: c-format.c:489 +#: c-format.c:491 msgid "fill character" msgstr "" -#: c-format.c:489 +#: c-format.c:491 msgid "fill character in strfmon format" msgstr "" -#: c-format.c:490 +#: c-format.c:492 msgid "the '^' strfmon flag" msgstr "" -#: c-format.c:491 +#: c-format.c:493 msgid "the '+' strfmon flag" msgstr "" -#: c-format.c:492 +#: c-format.c:494 msgid "'(' flag" msgstr "" -#: c-format.c:492 +#: c-format.c:494 msgid "the '(' strfmon flag" msgstr "" -#: c-format.c:493 +#: c-format.c:495 msgid "'!' flag" msgstr "" -#: c-format.c:493 +#: c-format.c:495 msgid "the '!' strfmon flag" msgstr "" -#: c-format.c:494 +#: c-format.c:496 msgid "the '-' strfmon flag" msgstr "" -#: c-format.c:495 +#: c-format.c:497 msgid "field width in strfmon format" msgstr "" -#: c-format.c:496 +#: c-format.c:498 msgid "left precision" msgstr "" -#: c-format.c:496 +#: c-format.c:498 msgid "left precision in strfmon format" msgstr "" -#: c-format.c:497 +#: c-format.c:499 msgid "right precision" msgstr "" -#: c-format.c:497 +#: c-format.c:499 msgid "right precision in strfmon format" msgstr "" -#: c-format.c:498 +#: c-format.c:500 msgid "length modifier in strfmon format" msgstr "" -#: c-format.c:1731 +#: c-format.c:1724 msgid "field precision" msgstr "" @@ -282,12 +282,12 @@ msgstr "" msgid "({anonymous})" msgstr "" -#: c-opts.c:1490 cp/error.c:990 fortran/cpp.c:552 +#: c-opts.c:1520 tree.c:3958 cp/error.c:1017 fortran/cpp.c:552 msgid "" msgstr "" #. Handle deferred options from command-line. -#: c-opts.c:1508 fortran/cpp.c:557 +#: c-opts.c:1538 fortran/cpp.c:557 msgid "" msgstr "" @@ -327,57 +327,52 @@ msgstr "" msgid "" msgstr "" -#: c-typeck.c:5268 +#: c-typeck.c:5466 msgid "array initialized from parenthesized string constant" msgstr "" -#: c-typeck.c:5338 c-typeck.c:6197 +#: c-typeck.c:5539 c-typeck.c:6410 msgid "initialization of a flexible array member" msgstr "" -#: c-typeck.c:5348 cp/typeck2.c:756 +#: c-typeck.c:5549 cp/typeck2.c:758 #, gcc-internal-format msgid "char-array initialized from wide string" msgstr "" -#: c-typeck.c:5356 +#: c-typeck.c:5557 msgid "wide character array initialized from non-wide string" msgstr "" -#: c-typeck.c:5362 +#: c-typeck.c:5563 msgid "wide character array initialized from incompatible wide string" msgstr "" -#: c-typeck.c:5380 cp/typeck2.c:784 -#, gcc-internal-format -msgid "initializer-string for array of chars is too long" -msgstr "" - -#: c-typeck.c:5386 +#: c-typeck.c:5597 msgid "array of inappropriate type initialized from string constant" msgstr "" #. ??? This should not be an error when inlining calls to #. unprototyped functions. -#: c-typeck.c:5453 c-typeck.c:4925 cp/typeck.c:1645 +#: c-typeck.c:5665 c-typeck.c:5118 cp/typeck.c:1658 #, gcc-internal-format msgid "invalid use of non-lvalue array" msgstr "" -#: c-typeck.c:5479 +#: c-typeck.c:5691 msgid "array initialized from non-constant array expression" msgstr "" -#: c-typeck.c:5493 c-typeck.c:5496 c-typeck.c:5504 c-typeck.c:5542 -#: c-typeck.c:6996 +#: c-typeck.c:5705 c-typeck.c:5708 c-typeck.c:5716 c-typeck.c:5755 +#: c-typeck.c:7209 msgid "initializer element is not constant" msgstr "" -#: c-typeck.c:5509 c-typeck.c:5554 c-typeck.c:7006 +#: c-typeck.c:5721 c-typeck.c:5767 c-typeck.c:7219 msgid "initializer element is not a constant expression" msgstr "" -#: c-typeck.c:5549 c-typeck.c:7001 +#: c-typeck.c:5762 c-typeck.c:7214 #, gcc-internal-format msgid "initializer element is not computable at load time" msgstr "" @@ -386,276 +381,287 @@ msgstr "" #. of VLAs themselves count as VLAs, it does not make #. sense to permit them to be initialized given that #. ordinary VLAs may not be initialized. -#: c-typeck.c:5563 c-decl.c:3337 c-decl.c:3352 +#: c-typeck.c:5776 c-decl.c:3921 c-decl.c:3936 #, gcc-internal-format msgid "variable-sized object may not be initialized" msgstr "" -#: c-typeck.c:5567 +#: c-typeck.c:5780 msgid "invalid initializer" msgstr "" -#: c-typeck.c:5776 +#: c-typeck.c:5989 msgid "(anonymous)" msgstr "" -#: c-typeck.c:6054 +#: c-typeck.c:6267 msgid "extra brace group at end of initializer" msgstr "" -#: c-typeck.c:6075 +#: c-typeck.c:6288 msgid "missing braces around initializer" msgstr "" -#: c-typeck.c:6136 +#: c-typeck.c:6349 msgid "braces around scalar initializer" msgstr "" -#: c-typeck.c:6194 +#: c-typeck.c:6407 msgid "initialization of flexible array member in a nested context" msgstr "" -#: c-typeck.c:6225 +#: c-typeck.c:6438 msgid "missing initializer" msgstr "" -#: c-typeck.c:6247 +#: c-typeck.c:6460 msgid "empty scalar initializer" msgstr "" -#: c-typeck.c:6252 +#: c-typeck.c:6465 msgid "extra elements in scalar initializer" msgstr "" -#: c-typeck.c:6360 c-typeck.c:6438 +#: c-typeck.c:6573 c-typeck.c:6651 msgid "array index in non-array initializer" msgstr "" -#: c-typeck.c:6365 c-typeck.c:6494 +#: c-typeck.c:6578 c-typeck.c:6707 msgid "field name not in record or union initializer" msgstr "" -#: c-typeck.c:6411 +#: c-typeck.c:6624 msgid "array index in initializer not of integer type" msgstr "" -#: c-typeck.c:6420 c-typeck.c:6429 +#: c-typeck.c:6633 c-typeck.c:6642 msgid "array index in initializer is not an integer constant expression" msgstr "" -#: c-typeck.c:6434 c-typeck.c:6436 +#: c-typeck.c:6647 c-typeck.c:6649 msgid "nonconstant array index in initializer" msgstr "" -#: c-typeck.c:6440 c-typeck.c:6443 +#: c-typeck.c:6653 c-typeck.c:6656 msgid "array index in initializer exceeds array bounds" msgstr "" -#: c-typeck.c:6457 +#: c-typeck.c:6670 msgid "empty index range in initializer" msgstr "" -#: c-typeck.c:6466 +#: c-typeck.c:6679 msgid "array index range in initializer exceeds array bounds" msgstr "" -#: c-typeck.c:6549 c-typeck.c:6576 c-typeck.c:7095 +#: c-typeck.c:6762 c-typeck.c:6789 c-typeck.c:7308 msgid "initialized field with side-effects overwritten" msgstr "" -#: c-typeck.c:6551 c-typeck.c:6578 c-typeck.c:7097 +#: c-typeck.c:6764 c-typeck.c:6791 c-typeck.c:7310 msgid "initialized field overwritten" msgstr "" -#: c-typeck.c:7023 c-typeck.c:4574 +#: c-typeck.c:7236 c-typeck.c:4761 #, gcc-internal-format msgid "enum conversion in initialization is invalid in C++" msgstr "" -#: c-typeck.c:7312 +#: c-typeck.c:7525 msgid "excess elements in char array initializer" msgstr "" -#: c-typeck.c:7319 c-typeck.c:7378 +#: c-typeck.c:7532 c-typeck.c:7591 msgid "excess elements in struct initializer" msgstr "" -#: c-typeck.c:7393 +#: c-typeck.c:7606 msgid "non-static initialization of a flexible array member" msgstr "" -#: c-typeck.c:7463 +#: c-typeck.c:7676 msgid "excess elements in union initializer" msgstr "" -#: c-typeck.c:7552 +#: c-typeck.c:7765 msgid "excess elements in array initializer" msgstr "" -#: c-typeck.c:7584 +#: c-typeck.c:7798 msgid "excess elements in vector initializer" msgstr "" -#: c-typeck.c:7614 +#: c-typeck.c:7829 msgid "excess elements in scalar initializer" msgstr "" -#: cfgrtl.c:1941 +#: cfgrtl.c:2026 msgid "flow control insn inside a basic block" msgstr "" -#: cfgrtl.c:2070 +#: cfgrtl.c:2157 msgid "wrong insn in the fallthru edge" msgstr "" -#: cfgrtl.c:2126 +#: cfgrtl.c:2211 msgid "insn outside basic block" msgstr "" -#: cfgrtl.c:2133 +#: cfgrtl.c:2218 msgid "return not followed by barrier" msgstr "" -#: collect2.c:396 gcc.c:7153 +#: collect2.c:486 gcc.c:7686 #, c-format msgid "internal gcc abort in %s, at %s:%d" msgstr "" -#: collect2.c:910 +#: collect2.c:939 +#, c-format +msgid "COLLECT_LTO_WRAPPER must be set." +msgstr "" + +#: collect2.c:1081 +#, c-format +msgid "too many lto output files" +msgstr "" + +#: collect2.c:1284 #, c-format msgid "no arguments" msgstr "" -#: collect2.c:1284 collect2.c:1432 collect2.c:1467 +#: collect2.c:1677 collect2.c:1839 collect2.c:1874 #, c-format msgid "fopen %s" msgstr "" -#: collect2.c:1287 collect2.c:1437 collect2.c:1470 +#: collect2.c:1680 collect2.c:1844 collect2.c:1877 #, c-format msgid "fclose %s" msgstr "" -#: collect2.c:1296 +#: collect2.c:1689 #, c-format msgid "collect2 version %s" msgstr "" -#: collect2.c:1386 +#: collect2.c:1785 #, c-format msgid "%d constructor(s) found\n" msgstr "" -#: collect2.c:1387 +#: collect2.c:1786 #, c-format msgid "%d destructor(s) found\n" msgstr "" -#: collect2.c:1388 +#: collect2.c:1787 #, c-format msgid "%d frame table(s) found\n" msgstr "" -#: collect2.c:1525 +#: collect2.c:1938 lto-wrapper.c:167 #, c-format msgid "can't get program status" msgstr "" -#: collect2.c:1594 +#: collect2.c:2007 #, c-format msgid "could not open response file %s" msgstr "" -#: collect2.c:1599 +#: collect2.c:2012 #, c-format msgid "could not write to response file %s" msgstr "" -#: collect2.c:1604 +#: collect2.c:2017 #, c-format msgid "could not close response file %s" msgstr "" -#: collect2.c:1622 +#: collect2.c:2035 #, c-format msgid "[cannot find %s]" msgstr "" -#: collect2.c:1637 +#: collect2.c:2050 #, c-format msgid "cannot find '%s'" msgstr "" -#: collect2.c:1641 collect2.c:2132 collect2.c:2287 gcc.c:3021 +#: collect2.c:2054 collect2.c:2577 collect2.c:2773 gcc.c:3075 +#: lto-wrapper.c:139 #, c-format msgid "pex_init failed" msgstr "" -#: collect2.c:1679 +#: collect2.c:2092 #, c-format msgid "[Leaving %s]\n" msgstr "" -#: collect2.c:1900 +#: collect2.c:2324 #, c-format msgid "" "\n" "write_c_file - output name is %s, prefix is %s\n" msgstr "" -#: collect2.c:2106 +#: collect2.c:2551 #, c-format msgid "cannot find 'nm'" msgstr "" -#: collect2.c:2153 +#: collect2.c:2599 #, c-format msgid "can't open nm output" msgstr "" -#: collect2.c:2197 +#: collect2.c:2682 #, c-format msgid "init function found in object %s" msgstr "" -#: collect2.c:2205 +#: collect2.c:2692 #, c-format msgid "fini function found in object %s" msgstr "" -#: collect2.c:2308 +#: collect2.c:2794 #, c-format msgid "can't open ldd output" msgstr "" -#: collect2.c:2311 +#: collect2.c:2797 #, c-format msgid "" "\n" "ldd output with constructors/destructors.\n" msgstr "" -#: collect2.c:2326 +#: collect2.c:2812 #, c-format msgid "dynamic dependency %s not found" msgstr "" -#: collect2.c:2338 +#: collect2.c:2824 #, c-format msgid "unable to open dynamic dependency '%s'" msgstr "" -#: collect2.c:2494 +#: collect2.c:2985 #, c-format msgid "%s: not a COFF file" msgstr "" -#: collect2.c:2614 +#: collect2.c:3115 #, c-format msgid "%s: cannot open as COFF file" msgstr "" -#: collect2.c:2672 +#: collect2.c:3173 #, c-format msgid "library lib%s not found" msgstr "" @@ -670,12 +676,12 @@ msgstr "" msgid "too many input files" msgstr "" -#: diagnostic.c:190 +#: diagnostic.c:185 #, c-format msgid "compilation terminated due to -Wfatal-errors.\n" msgstr "" -#: diagnostic.c:199 +#: diagnostic.c:194 #, c-format msgid "" "Please submit a full bug report,\n" @@ -683,66 +689,66 @@ msgid "" "See %s for instructions.\n" msgstr "" -#: diagnostic.c:208 +#: diagnostic.c:203 #, c-format msgid "compilation terminated.\n" msgstr "" -#: diagnostic.c:377 +#: diagnostic.c:381 #, c-format msgid "" "*** WARNING *** there are active plugins, do not report this as a bug unless " "you can reproduce it without enabling any plugins.\n" msgstr "" -#: diagnostic.c:394 +#: diagnostic.c:398 #, c-format msgid "%s:%d: confused by earlier errors, bailing out\n" msgstr "" -#: diagnostic.c:705 +#: diagnostic.c:709 #, c-format msgid "Internal compiler error: Error reporting routines re-entered.\n" msgstr "" -#: final.c:1134 +#: final.c:1152 msgid "negative insn length" msgstr "" -#: final.c:2608 +#: final.c:2651 msgid "could not split insn" msgstr "" -#: final.c:3005 +#: final.c:3085 msgid "invalid 'asm': " msgstr "" -#: final.c:3188 +#: final.c:3268 #, c-format msgid "nested assembly dialect alternatives" msgstr "" -#: final.c:3205 final.c:3217 +#: final.c:3285 final.c:3297 #, c-format msgid "unterminated assembly dialect alternative" msgstr "" -#: final.c:3264 +#: final.c:3344 #, c-format msgid "operand number missing after %%-letter" msgstr "" -#: final.c:3267 final.c:3308 +#: final.c:3347 final.c:3388 #, c-format msgid "operand number out of range" msgstr "" -#: final.c:3327 +#: final.c:3407 #, c-format msgid "invalid %%-code" msgstr "" -#: final.c:3357 +#: final.c:3437 #, c-format msgid "'%%l' operand isn't a label" msgstr "" @@ -753,118 +759,118 @@ msgstr "" #. handle them. #. We can't handle floating point constants; #. PRINT_OPERAND must handle them. -#: final.c:3503 vmsdbgout.c:488 config/i386/i386.c:10285 -#: config/pdp11/pdp11.c:1677 +#: final.c:3583 vmsdbgout.c:495 config/i386/i386.c:10677 +#: config/pdp11/pdp11.c:1682 #, c-format msgid "floating constant misused" msgstr "" -#: final.c:3565 vmsdbgout.c:545 config/i386/i386.c:10372 -#: config/pdp11/pdp11.c:1724 +#: final.c:3645 vmsdbgout.c:552 config/i386/i386.c:10764 +#: config/pdp11/pdp11.c:1729 #, c-format msgid "invalid expression as operand" msgstr "" -#: gcc.c:1736 +#: gcc.c:1789 #, c-format msgid "Using built-in specs.\n" msgstr "" -#: gcc.c:1921 +#: gcc.c:1974 #, c-format msgid "" "Setting spec %s to '%s'\n" "\n" msgstr "" -#: gcc.c:2036 +#: gcc.c:2089 #, c-format msgid "Reading specs from %s\n" msgstr "" -#: gcc.c:2132 gcc.c:2151 +#: gcc.c:2185 gcc.c:2204 #, c-format msgid "specs %%include syntax malformed after %ld characters" msgstr "" -#: gcc.c:2159 +#: gcc.c:2212 #, c-format msgid "could not find specs file %s\n" msgstr "" -#: gcc.c:2176 gcc.c:2184 gcc.c:2193 gcc.c:2202 +#: gcc.c:2229 gcc.c:2237 gcc.c:2246 gcc.c:2255 #, c-format msgid "specs %%rename syntax malformed after %ld characters" msgstr "" -#: gcc.c:2211 +#: gcc.c:2264 #, c-format msgid "specs %s spec was not found to be renamed" msgstr "" -#: gcc.c:2218 +#: gcc.c:2271 #, c-format msgid "%s: attempt to rename spec '%s' to already defined spec '%s'" msgstr "" -#: gcc.c:2223 +#: gcc.c:2276 #, c-format msgid "rename spec %s to %s\n" msgstr "" -#: gcc.c:2225 +#: gcc.c:2278 #, c-format msgid "" "spec is '%s'\n" "\n" msgstr "" -#: gcc.c:2238 +#: gcc.c:2291 #, c-format msgid "specs unknown %% command after %ld characters" msgstr "" -#: gcc.c:2249 gcc.c:2262 +#: gcc.c:2302 gcc.c:2315 #, c-format msgid "specs file malformed after %ld characters" msgstr "" -#: gcc.c:2314 +#: gcc.c:2367 #, c-format msgid "spec file has no spec for linking" msgstr "" -#: gcc.c:2642 gcc.c:4954 +#: gcc.c:2695 gcc.c:5233 #, c-format msgid "%s\n" msgstr "" -#: gcc.c:2843 +#: gcc.c:2896 #, c-format msgid "system path '%s' is not absolute" msgstr "" -#: gcc.c:2915 +#: gcc.c:2968 #, c-format msgid "-pipe not supported" msgstr "" -#: gcc.c:2977 +#: gcc.c:3030 #, c-format msgid "" "\n" "Go ahead? (y or n) " msgstr "" -#: gcc.c:3060 +#: gcc.c:3114 msgid "failed to get exit status" msgstr "" -#: gcc.c:3066 +#: gcc.c:3120 msgid "failed to get process times" msgstr "" -#: gcc.c:3092 +#: gcc.c:3146 #, c-format msgid "" "Internal error: %s (program %s)\n" @@ -872,225 +878,231 @@ msgid "" "See %s for instructions." msgstr "" -#: gcc.c:3118 +#: gcc.c:3174 #, c-format msgid "# %s %.2f %.2f\n" msgstr "" -#: gcc.c:3252 +#: gcc.c:3365 #, c-format msgid "Usage: %s [options] file...\n" msgstr "" -#: gcc.c:3253 +#: gcc.c:3366 msgid "Options:\n" msgstr "" -#: gcc.c:3255 +#: gcc.c:3368 msgid " -pass-exit-codes Exit with highest error code from a phase\n" msgstr "" -#: gcc.c:3256 +#: gcc.c:3369 msgid " --help Display this information\n" msgstr "" -#: gcc.c:3257 +#: gcc.c:3370 msgid "" " --target-help Display target specific command line options\n" msgstr "" -#: gcc.c:3258 +#: gcc.c:3371 msgid "" " --help={target|optimizers|warnings|params|[^]{joined|separate|" "undocumented}}[,...]\n" msgstr "" -#: gcc.c:3259 +#: gcc.c:3372 msgid "" " Display specific types of command line options\n" msgstr "" -#: gcc.c:3261 +#: gcc.c:3374 msgid " (Use '-v --help' to display command line options of sub-processes)\n" msgstr "" -#: gcc.c:3262 +#: gcc.c:3375 msgid " --version Display compiler version information\n" msgstr "" -#: gcc.c:3263 +#: gcc.c:3376 msgid " -dumpspecs Display all of the built in spec strings\n" msgstr "" -#: gcc.c:3264 +#: gcc.c:3377 msgid " -dumpversion Display the version of the compiler\n" msgstr "" -#: gcc.c:3265 +#: gcc.c:3378 msgid " -dumpmachine Display the compiler's target processor\n" msgstr "" -#: gcc.c:3266 +#: gcc.c:3379 msgid "" " -print-search-dirs Display the directories in the compiler's search " "path\n" msgstr "" -#: gcc.c:3267 +#: gcc.c:3380 msgid "" " -print-libgcc-file-name Display the name of the compiler's companion " "library\n" msgstr "" -#: gcc.c:3268 +#: gcc.c:3381 msgid " -print-file-name= Display the full path to library \n" msgstr "" -#: gcc.c:3269 +#: gcc.c:3382 msgid "" " -print-prog-name= Display the full path to compiler component " "\n" msgstr "" -#: gcc.c:3270 +#: gcc.c:3383 msgid "" " -print-multi-directory Display the root directory for versions of " "libgcc\n" msgstr "" -#: gcc.c:3271 +#: gcc.c:3384 msgid "" " -print-multi-lib Display the mapping between command line options " "and\n" " multiple library search directories\n" msgstr "" -#: gcc.c:3274 +#: gcc.c:3387 msgid " -print-multi-os-directory Display the relative path to OS libraries\n" msgstr "" -#: gcc.c:3275 +#: gcc.c:3388 msgid " -print-sysroot Display the target libraries directory\n" msgstr "" -#: gcc.c:3276 +#: gcc.c:3389 msgid "" " -print-sysroot-headers-suffix Display the sysroot suffix used to find " "headers\n" msgstr "" -#: gcc.c:3277 +#: gcc.c:3390 msgid "" " -Wa, Pass comma-separated on to the " "assembler\n" msgstr "" -#: gcc.c:3278 +#: gcc.c:3391 msgid "" " -Wp, Pass comma-separated on to the " "preprocessor\n" msgstr "" -#: gcc.c:3279 +#: gcc.c:3392 msgid "" " -Wl, Pass comma-separated on to the linker\n" msgstr "" -#: gcc.c:3280 +#: gcc.c:3393 msgid " -Xassembler Pass on to the assembler\n" msgstr "" -#: gcc.c:3281 +#: gcc.c:3394 msgid " -Xpreprocessor Pass on to the preprocessor\n" msgstr "" -#: gcc.c:3282 +#: gcc.c:3395 msgid " -Xlinker Pass on to the linker\n" msgstr "" -#: gcc.c:3283 +#: gcc.c:3396 msgid "" " -combine Pass multiple source files to compiler at once\n" msgstr "" -#: gcc.c:3284 +#: gcc.c:3397 msgid " -save-temps Do not delete intermediate files\n" msgstr "" -#: gcc.c:3285 +#: gcc.c:3398 msgid " -save-temps= Do not delete intermediate files\n" msgstr "" -#: gcc.c:3286 +#: gcc.c:3399 +msgid "" +" -no-canonical-prefixes Do not canonicalize paths when building relative\n" +" prefixes to other gcc components\n" +msgstr "" + +#: gcc.c:3402 msgid " -pipe Use pipes rather than intermediate files\n" msgstr "" -#: gcc.c:3287 +#: gcc.c:3403 msgid " -time Time the execution of each subprocess\n" msgstr "" -#: gcc.c:3288 +#: gcc.c:3404 msgid "" " -specs= Override built-in specs with the contents of " "\n" msgstr "" -#: gcc.c:3289 +#: gcc.c:3405 msgid "" " -std= Assume that the input sources are for \n" msgstr "" -#: gcc.c:3290 +#: gcc.c:3406 msgid "" " --sysroot= Use as the root directory for " "headers\n" " and libraries\n" msgstr "" -#: gcc.c:3293 +#: gcc.c:3409 msgid "" " -B Add to the compiler's search paths\n" msgstr "" -#: gcc.c:3294 +#: gcc.c:3410 msgid " -b Run gcc for target , if installed\n" msgstr "" -#: gcc.c:3295 +#: gcc.c:3411 msgid "" " -V Run gcc version number , if installed\n" msgstr "" -#: gcc.c:3296 +#: gcc.c:3412 msgid "" " -v Display the programs invoked by the compiler\n" msgstr "" -#: gcc.c:3297 +#: gcc.c:3413 msgid "" " -### Like -v but options quoted and commands not " "executed\n" msgstr "" -#: gcc.c:3298 +#: gcc.c:3414 msgid "" " -E Preprocess only; do not compile, assemble or " "link\n" msgstr "" -#: gcc.c:3299 +#: gcc.c:3415 msgid " -S Compile only; do not assemble or link\n" msgstr "" -#: gcc.c:3300 +#: gcc.c:3416 msgid " -c Compile and assemble, but do not link\n" msgstr "" -#: gcc.c:3301 +#: gcc.c:3417 msgid " -o Place the output into \n" msgstr "" -#: gcc.c:3302 +#: gcc.c:3418 msgid "" " -x Specify the language of the following input " "files\n" @@ -1101,7 +1113,7 @@ msgid "" "extension\n" msgstr "" -#: gcc.c:3309 +#: gcc.c:3425 #, c-format msgid "" "\n" @@ -1110,201 +1122,206 @@ msgid "" " other options on to these processes the -W options must be used.\n" msgstr "" -#: gcc.c:3439 +#: gcc.c:3557 #, c-format msgid "'-%c' option must have argument" msgstr "" -#: gcc.c:3465 +#: gcc.c:3583 #, c-format msgid "couldn't run '%s': %s" msgstr "" -#: gcc.c:3467 +#: gcc.c:3585 #, c-format msgid "couldn't run '%s': %s: %s" msgstr "" -#: gcc.c:3792 +#: gcc.c:3963 #, c-format msgid "argument to '-Xlinker' is missing" msgstr "" -#: gcc.c:3800 +#: gcc.c:3971 #, c-format msgid "argument to '-Xpreprocessor' is missing" msgstr "" -#: gcc.c:3807 +#: gcc.c:3978 #, c-format msgid "argument to '-Xassembler' is missing" msgstr "" -#: gcc.c:3814 +#: gcc.c:3985 #, c-format msgid "argument to '-l' is missing" msgstr "" -#: gcc.c:3835 +#: gcc.c:4006 #, c-format msgid "'%s' is an unknown -save-temps option" msgstr "" -#: gcc.c:3846 +#: gcc.c:4020 #, c-format msgid "argument to '-specs' is missing" msgstr "" -#: gcc.c:3860 +#: gcc.c:4034 #, c-format msgid "argument to '-specs=' is missing" msgstr "" -#: gcc.c:3882 +#: gcc.c:4062 #, c-format msgid "argument to '-wrapper' is missing" msgstr "" -#: gcc.c:3910 +#: gcc.c:4090 #, c-format msgid "'-%c' must come at the start of the command line" msgstr "" -#: gcc.c:3919 +#: gcc.c:4099 #, c-format msgid "argument to '-B' is missing" msgstr "" -#: gcc.c:4294 +#: gcc.c:4492 #, c-format msgid "argument to '-x' is missing" msgstr "" -#: gcc.c:4322 +#: gcc.c:4520 gcc.c:4951 #, c-format msgid "argument to '-%s' is missing" msgstr "" -#: gcc.c:4695 +#: gcc.c:4746 +#, c-format +msgid "unable to locate default linker script '%s' in the library search paths" +msgstr "" + +#: gcc.c:4927 #, c-format msgid "switch '%s' does not start with '-'" msgstr "" -#: gcc.c:4770 +#: gcc.c:5043 #, c-format msgid "could not open temporary response file %s" msgstr "" -#: gcc.c:4776 +#: gcc.c:5049 #, c-format msgid "could not write to temporary response file %s" msgstr "" -#: gcc.c:4782 +#: gcc.c:5055 #, c-format msgid "could not close temporary response file %s" msgstr "" -#: gcc.c:4882 +#: gcc.c:5157 #, c-format msgid "spec '%s' invalid" msgstr "" -#: gcc.c:5027 +#: gcc.c:5306 #, c-format msgid "spec '%s' has invalid '%%0%c'" msgstr "" -#: gcc.c:5326 +#: gcc.c:5615 #, c-format msgid "spec '%s' has invalid '%%W%c" msgstr "" -#: gcc.c:5346 +#: gcc.c:5635 #, c-format msgid "spec '%s' has invalid '%%x%c'" msgstr "" -#: gcc.c:5568 +#: gcc.c:5857 #, c-format msgid "Processing spec %c%s%c, which is '%s'\n" msgstr "" -#: gcc.c:5692 +#: gcc.c:5982 #, c-format msgid "unknown spec function '%s'" msgstr "" -#: gcc.c:5711 +#: gcc.c:6002 #, c-format msgid "error in args to spec function '%s'" msgstr "" -#: gcc.c:5759 +#: gcc.c:6051 #, c-format msgid "malformed spec function name" msgstr "" #. ) -#: gcc.c:5762 +#: gcc.c:6054 #, c-format msgid "no arguments for spec function" msgstr "" -#: gcc.c:5781 +#: gcc.c:6073 #, c-format msgid "malformed spec function arguments" msgstr "" -#: gcc.c:6027 +#: gcc.c:6319 #, c-format msgid "braced spec '%s' is invalid at '%c'" msgstr "" -#: gcc.c:6115 +#: gcc.c:6407 #, c-format msgid "braced spec body '%s' is invalid" msgstr "" -#: gcc.c:6644 +#: gcc.c:7106 #, c-format msgid "install: %s%s\n" msgstr "" -#: gcc.c:6647 +#: gcc.c:7109 #, c-format msgid "programs: %s\n" msgstr "" -#: gcc.c:6649 +#: gcc.c:7111 #, c-format msgid "libraries: %s\n" msgstr "" #. The error status indicates that only one set of fixed #. headers should be built. -#: gcc.c:6715 +#: gcc.c:7177 #, c-format msgid "not configured with sysroot headers suffix" msgstr "" -#: gcc.c:6724 +#: gcc.c:7186 #, c-format msgid "" "\n" "For bug reporting instructions, please see:\n" msgstr "" -#: gcc.c:6740 +#: gcc.c:7202 #, c-format msgid "%s %s%s\n" msgstr "" -#: gcc.c:6743 gcov.c:430 fortran/gfortranspec.c:383 java/jcf-dump.c:1170 +#: gcc.c:7205 gcov.c:430 fortran/gfortranspec.c:373 java/jcf-dump.c:1170 msgid "(C)" msgstr "" -#: gcc.c:6744 java/jcf-dump.c:1171 +#: gcc.c:7206 java/jcf-dump.c:1171 #, c-format msgid "" "This is free software; see the source for copying conditions. There is NO\n" @@ -1312,47 +1329,57 @@ msgid "" "\n" msgstr "" -#: gcc.c:6761 +#: gcc.c:7223 #, c-format msgid "Target: %s\n" msgstr "" -#: gcc.c:6762 +#: gcc.c:7224 #, c-format msgid "Configured with: %s\n" msgstr "" -#: gcc.c:6776 +#: gcc.c:7238 #, c-format msgid "Thread model: %s\n" msgstr "" -#: gcc.c:6787 +#: gcc.c:7249 #, c-format msgid "gcc version %s %s\n" msgstr "" -#: gcc.c:6789 +#: gcc.c:7251 #, c-format msgid "gcc driver version %s %sexecuting gcc version %s\n" msgstr "" -#: gcc.c:6797 +#: gcc.c:7259 #, c-format msgid "no input files" msgstr "" -#: gcc.c:6846 +#: gcc.c:7308 #, c-format -msgid "cannot specify -o with -c or -S with multiple files" +msgid "cannot specify -o with -c, -S or -E with multiple files" msgstr "" -#: gcc.c:6880 +#: gcc.c:7342 #, c-format msgid "spec '%s' is invalid" msgstr "" -#: gcc.c:7016 +#: gcc.c:7533 +#, c-format +msgid "-use-linker-plugin, but liblto_plugin.so not found" +msgstr "" + +#: gcc.c:7538 +#, c-format +msgid "could not find libgcc.a" +msgstr "" + +#: gcc.c:7549 #, c-format msgid "" "\n" @@ -1361,59 +1388,59 @@ msgid "" "\n" msgstr "" -#: gcc.c:7017 +#: gcc.c:7550 #, c-format msgid "" "Use \"-Wl,OPTION\" to pass \"OPTION\" to the linker.\n" "\n" msgstr "" -#: gcc.c:7369 +#: gcc.c:7902 #, c-format msgid "multilib spec '%s' is invalid" msgstr "" -#: gcc.c:7560 +#: gcc.c:8093 #, c-format msgid "multilib exclusions '%s' is invalid" msgstr "" -#: gcc.c:7618 gcc.c:7759 +#: gcc.c:8151 gcc.c:8292 #, c-format msgid "multilib select '%s' is invalid" msgstr "" -#: gcc.c:7797 +#: gcc.c:8330 #, c-format msgid "multilib exclusion '%s' is invalid" msgstr "" -#: gcc.c:8003 +#: gcc.c:8536 #, c-format msgid "environment variable \"%s\" not defined" msgstr "" -#: gcc.c:8094 gcc.c:8099 +#: gcc.c:8627 gcc.c:8632 #, c-format msgid "invalid version number `%s'" msgstr "" -#: gcc.c:8142 +#: gcc.c:8675 #, c-format msgid "too few arguments to %%:version-compare" msgstr "" -#: gcc.c:8148 +#: gcc.c:8681 #, c-format msgid "too many arguments to %%:version-compare" msgstr "" -#: gcc.c:8189 +#: gcc.c:8722 #, c-format msgid "unknown operator '%s' in %%:version-compare" msgstr "" -#: gcc.c:8223 +#: gcc.c:8756 #, c-format msgid "" "Assembler options\n" @@ -1421,13 +1448,38 @@ msgid "" "\n" msgstr "" -#: gcc.c:8224 +#: gcc.c:8757 #, c-format msgid "" "Use \"-Wa,OPTION\" to pass \"OPTION\" to the assembler.\n" "\n" msgstr "" +#: gcc.c:8803 +#, c-format +msgid "too many arguments to %%:compare-debug-dump-opt" +msgstr "" + +#: gcc.c:8870 +#, c-format +msgid "too many arguments to %%:compare-debug-self-opt" +msgstr "" + +#: gcc.c:8905 +#, c-format +msgid "too few arguments to %%:compare-debug-auxbase-opt" +msgstr "" + +#: gcc.c:8908 +#, c-format +msgid "too many arguments to %%:compare-debug-auxbase-opt" +msgstr "" + +#: gcc.c:8915 +#, c-format +msgid "argument to %%:compare-debug-auxbase-opt does not end in .gk" +msgstr "" + #: gcov.c:403 #, c-format msgid "" @@ -1608,130 +1660,130 @@ msgstr "" msgid "%s:stamp mismatch with graph file\n" msgstr "" -#: gcov.c:1082 +#: gcov.c:1083 #, c-format msgid "%s:unknown function '%u'\n" msgstr "" -#: gcov.c:1095 +#: gcov.c:1097 #, c-format msgid "%s:profile mismatch for '%s'\n" msgstr "" -#: gcov.c:1114 +#: gcov.c:1116 #, c-format msgid "%s:overflowed\n" msgstr "" -#: gcov.c:1138 +#: gcov.c:1140 #, c-format msgid "%s:'%s' lacks entry and/or exit blocks\n" msgstr "" -#: gcov.c:1143 +#: gcov.c:1145 #, c-format msgid "%s:'%s' has arcs to entry block\n" msgstr "" -#: gcov.c:1151 +#: gcov.c:1153 #, c-format msgid "%s:'%s' has arcs from exit block\n" msgstr "" -#: gcov.c:1359 +#: gcov.c:1361 #, c-format msgid "%s:graph is unsolvable for '%s'\n" msgstr "" -#: gcov.c:1439 +#: gcov.c:1441 #, c-format msgid "%s '%s'\n" msgstr "" -#: gcov.c:1442 +#: gcov.c:1444 #, c-format msgid "Lines executed:%s of %d\n" msgstr "" -#: gcov.c:1446 +#: gcov.c:1448 #, c-format msgid "No executable lines\n" msgstr "" -#: gcov.c:1452 +#: gcov.c:1454 #, c-format msgid "Branches executed:%s of %d\n" msgstr "" -#: gcov.c:1456 +#: gcov.c:1458 #, c-format msgid "Taken at least once:%s of %d\n" msgstr "" -#: gcov.c:1462 +#: gcov.c:1464 #, c-format msgid "No branches\n" msgstr "" -#: gcov.c:1464 +#: gcov.c:1466 #, c-format msgid "Calls executed:%s of %d\n" msgstr "" -#: gcov.c:1468 +#: gcov.c:1470 #, c-format msgid "No calls\n" msgstr "" -#: gcov.c:1628 +#: gcov.c:1630 #, c-format msgid "%s:no lines for '%s'\n" msgstr "" -#: gcov.c:1823 +#: gcov.c:1825 #, c-format msgid "call %2d returned %s\n" msgstr "" -#: gcov.c:1828 +#: gcov.c:1830 #, c-format msgid "call %2d never executed\n" msgstr "" -#: gcov.c:1833 +#: gcov.c:1835 #, c-format msgid "branch %2d taken %s%s\n" msgstr "" -#: gcov.c:1837 +#: gcov.c:1839 #, c-format msgid "branch %2d never executed\n" msgstr "" -#: gcov.c:1842 +#: gcov.c:1844 #, c-format msgid "unconditional %2d taken %s\n" msgstr "" -#: gcov.c:1845 +#: gcov.c:1847 #, c-format msgid "unconditional %2d never executed\n" msgstr "" -#: gcov.c:1881 +#: gcov.c:1883 #, c-format msgid "%s:cannot open source file\n" msgstr "" -#: gcse.c:3944 +#: gcse.c:3967 msgid "PRE disabled" msgstr "" -#: gcse.c:4425 +#: gcse.c:4448 msgid "GCSE disabled" msgstr "" -#: gcse.c:4942 +#: gcse.c:4965 msgid "const/copy propagation disabled" msgstr "" @@ -1775,155 +1827,195 @@ msgstr "" msgid "'" msgstr "" -#: langhooks.c:362 +#: langhooks.c:355 msgid "At top level:" msgstr "" -#: langhooks.c:382 cp/error.c:2661 +#: langhooks.c:375 cp/error.c:2710 #, c-format msgid "In member function %qs" msgstr "" -#: langhooks.c:386 cp/error.c:2664 +#: langhooks.c:379 cp/error.c:2713 #, c-format msgid "In function %qs" msgstr "" -#: langhooks.c:437 cp/error.c:2620 +#: langhooks.c:430 cp/error.c:2663 #, c-format msgid " inlined from %qs at %s:%d:%d" msgstr "" -#: langhooks.c:442 cp/error.c:2625 +#: langhooks.c:435 cp/error.c:2668 #, c-format msgid " inlined from %qs at %s:%d" msgstr "" -#: langhooks.c:448 cp/error.c:2631 +#: langhooks.c:441 cp/error.c:2674 #, c-format msgid " inlined from %qs" msgstr "" -#: loop-iv.c:2965 tree-ssa-loop-niter.c:1871 +#: loop-iv.c:2966 tree-ssa-loop-niter.c:1874 msgid "assuming that the loop is not infinite" msgstr "" -#: loop-iv.c:2966 tree-ssa-loop-niter.c:1872 +#: loop-iv.c:2967 tree-ssa-loop-niter.c:1875 msgid "cannot optimize possibly infinite loops" msgstr "" -#: loop-iv.c:2974 tree-ssa-loop-niter.c:1876 +#: loop-iv.c:2975 tree-ssa-loop-niter.c:1879 msgid "assuming that the loop counter does not overflow" msgstr "" -#: loop-iv.c:2975 tree-ssa-loop-niter.c:1877 +#: loop-iv.c:2976 tree-ssa-loop-niter.c:1880 msgid "cannot optimize loop, the loop counter may overflow" msgstr "" +#: lto-wrapper.c:176 +#, c-format +msgid "%s terminated with signal %d [%s], core dumped" +msgstr "" + +#: lto-wrapper.c:179 +#, c-format +msgid "%s terminated with signal %d [%s]" +msgstr "" + +#: lto-wrapper.c:184 collect2.c:1964 +#, gcc-internal-format +msgid "%s returned %d exit status" +msgstr "" + +#: lto-wrapper.c:199 +#, c-format +msgid "deleting LTRANS file %s" +msgstr "" + +#: lto-wrapper.c:221 +#, c-format +msgid "failed to open %s" +msgstr "" + +#: lto-wrapper.c:226 +#, c-format +msgid "could not write to temporary file %s" +msgstr "" + +#: lto-wrapper.c:288 lto-wrapper.c:345 +#, c-format +msgid "invalid LTO mode" +msgstr "" + +#: lto-wrapper.c:336 +#, c-format +msgid "fopen: %s" +msgstr "" + #. What to print when a switch has no documentation. -#: opts.c:339 +#: opts.c:341 msgid "This switch lacks documentation" msgstr "" -#: opts.c:1265 +#: opts.c:1289 msgid "[enabled]" msgstr "" -#: opts.c:1265 +#: opts.c:1289 msgid "[disabled]" msgstr "" -#: opts.c:1280 +#: opts.c:1304 #, c-format msgid " No options with the desired characteristics were found\n" msgstr "" -#: opts.c:1289 +#: opts.c:1313 #, c-format msgid "" " None found. Use --help=%s to show *all* the options supported by the %s " "front-end\n" msgstr "" -#: opts.c:1295 +#: opts.c:1319 #, c-format msgid "" " All options with the desired characteristics have already been displayed\n" msgstr "" -#: opts.c:1349 +#: opts.c:1373 msgid "The following options are target specific" msgstr "" -#: opts.c:1352 +#: opts.c:1376 msgid "The following options control compiler warning messages" msgstr "" -#: opts.c:1355 +#: opts.c:1379 msgid "The following options control optimizations" msgstr "" -#: opts.c:1358 opts.c:1397 +#: opts.c:1382 opts.c:1421 msgid "The following options are language-independent" msgstr "" -#: opts.c:1361 +#: opts.c:1385 msgid "The --param option recognizes the following as parameters" msgstr "" -#: opts.c:1367 +#: opts.c:1391 msgid "The following options are specific to just the language " msgstr "" -#: opts.c:1369 +#: opts.c:1393 msgid "The following options are supported by the language " msgstr "" -#: opts.c:1380 +#: opts.c:1404 msgid "The following options are not documented" msgstr "" -#: opts.c:1382 +#: opts.c:1406 msgid "The following options take separate arguments" msgstr "" -#: opts.c:1384 +#: opts.c:1408 msgid "The following options take joined arguments" msgstr "" -#: opts.c:1395 +#: opts.c:1419 msgid "The following options are language-related" msgstr "" -#: opts.c:1555 +#: opts.c:1579 #, c-format msgid "warning: --help argument %.*s is ambiguous, please be more specific\n" msgstr "" -#: opts.c:1563 +#: opts.c:1587 #, c-format msgid "warning: unrecognized argument to --help= option: %.*s\n" msgstr "" -#: reload.c:3780 +#: reload.c:3813 msgid "unable to generate reloads for:" msgstr "" -#: reload1.c:2094 +#: reload1.c:2151 msgid "this is the insn:" msgstr "" #. It's the compiler's fault. -#: reload1.c:5619 +#: reload1.c:5671 msgid "could not find a spill register" msgstr "" #. It's the compiler's fault. -#: reload1.c:7597 +#: reload1.c:7656 msgid "VOIDmode on an output" msgstr "" -#: reload1.c:8352 +#: reload1.c:8411 msgid "Failure trying to reload:" msgstr "" @@ -1981,70 +2073,75 @@ msgstr "" msgid "collect: relinking\n" msgstr "" -#: toplev.c:606 +#: toplev.c:621 #, c-format msgid "unrecoverable error" msgstr "" -#: toplev.c:1168 +#: toplev.c:1196 #, c-format msgid "" "%s%s%s %sversion %s (%s)\n" "%s\tcompiled by GNU C version %s, " msgstr "" -#: toplev.c:1170 +#: toplev.c:1198 #, c-format msgid "%s%s%s %sversion %s (%s) compiled by CC, " msgstr "" -#: toplev.c:1174 +#: toplev.c:1203 #, c-format -msgid "GMP version %s, MPFR version %s.\n" +msgid "GMP version %s, MPFR version %s, MPC version %s\n" msgstr "" -#: toplev.c:1176 +#: toplev.c:1206 +#, c-format +msgid "GMP version %s, MPFR version %s\n" +msgstr "" + +#: toplev.c:1209 #, c-format msgid "%s%swarning: %s header version %s differs from library version %s.\n" msgstr "" -#: toplev.c:1178 +#: toplev.c:1211 #, c-format msgid "" "%s%sGGC heuristics: --param ggc-min-expand=%d --param ggc-min-heapsize=%d\n" msgstr "" -#: toplev.c:1336 +#: toplev.c:1380 msgid "options passed: " msgstr "" -#: toplev.c:1370 +#: toplev.c:1414 msgid "options enabled: " msgstr "" -#: toplev.c:1505 +#: toplev.c:1549 #, c-format msgid "created and used with differing settings of '%s'" msgstr "" -#: toplev.c:1507 +#: toplev.c:1551 msgid "out of memory" msgstr "" -#: toplev.c:1522 +#: toplev.c:1566 msgid "created and used with different settings of -fpic" msgstr "" -#: toplev.c:1524 +#: toplev.c:1568 msgid "created and used with different settings of -fpie" msgstr "" -#: tree-vrp.c:6517 +#: tree-vrp.c:6516 msgid "" "assuming signed overflow does not occur when simplifying && or || to & or |" msgstr "" -#: tree-vrp.c:6521 +#: tree-vrp.c:6520 msgid "" "assuming signed overflow does not occur when simplifying ==, != or ! to " "identity or ^" @@ -2167,956 +2264,985 @@ msgstr "" msgid "permerror: " msgstr "" -#: params.def:47 -msgid "" -"The maximum structure size (in bytes) for which GCC will use by-element " -"copies" -msgstr "" - -#: params.def:56 -msgid "" -"The maximum number of structure fields for which GCC will use by-element " -"copies" -msgstr "" - -#: params.def:68 -msgid "" -"The threshold ratio between instantiated fields and the total structure size" -msgstr "" - -#: params.def:78 +#: params.def:48 msgid "The threshold ratio between current and hottest structure counts" msgstr "" -#: params.def:85 +#: params.def:55 msgid "Maximal esitmated outcome of branch considered predictable" msgstr "" -#: params.def:102 +#: params.def:72 msgid "" "The maximum number of instructions in a single function eligible for inlining" msgstr "" -#: params.def:114 +#: params.def:84 msgid "The maximum number of instructions when automatically inlining" msgstr "" -#: params.def:119 +#: params.def:89 msgid "" "The maximum number of instructions inline function can grow to via recursive " "inlining" msgstr "" -#: params.def:124 +#: params.def:94 msgid "" "The maximum number of instructions non-inline function can grow to via " "recursive inlining" msgstr "" -#: params.def:129 +#: params.def:99 msgid "The maximum depth of recursive inlining for inline functions" msgstr "" -#: params.def:134 +#: params.def:104 msgid "The maximum depth of recursive inlining for non-inline functions" msgstr "" -#: params.def:139 +#: params.def:109 msgid "" "Inline recursively only when the probability of call being executed exceeds " "the parameter" msgstr "" -#: params.def:146 +#: params.def:117 +msgid "" +"The maximum number of nested indirect inlining performed by early inliner" +msgstr "" + +#: params.def:124 msgid "" "If -fvariable-expansion-in-unroller is used, the maximum number of times " "that an individual variable will be expanded during loop unrolling" msgstr "" -#: params.def:152 +#: params.def:130 msgid "" "If -ftree-vectorize is used, the minimal loop bound of a loop to be " "considered for vectorization" msgstr "" -#: params.def:163 +#: params.def:141 msgid "The maximum number of instructions to consider to fill a delay slot" msgstr "" -#: params.def:174 +#: params.def:152 msgid "" "The maximum number of instructions to consider to find accurate live " "register information" msgstr "" -#: params.def:184 +#: params.def:162 msgid "The maximum length of scheduling's pending operations list" msgstr "" -#: params.def:189 +#: params.def:167 msgid "The size of function body to be considered large" msgstr "" -#: params.def:193 +#: params.def:171 msgid "Maximal growth due to inlining of large function (in percent)" msgstr "" -#: params.def:197 +#: params.def:175 msgid "The size of translation unit to be considered large" msgstr "" -#: params.def:201 +#: params.def:179 msgid "" "how much can given compilation unit grow because of the inlining (in percent)" msgstr "" -#: params.def:205 +#: params.def:183 msgid "" "how much can given compilation unit grow because of the interprocedural " "constant propagation (in percent)" msgstr "" -#: params.def:209 -msgid "expense of call operation relative to ordinary arithmetic operations" +#: params.def:187 +msgid "" +"maximal estimated growth of function body caused by early inlining of single " +"call" msgstr "" -#: params.def:213 +#: params.def:191 msgid "The size of stack frame to be considered large" msgstr "" -#: params.def:217 +#: params.def:195 msgid "Maximal stack frame growth due to inlining (in percent)" msgstr "" -#: params.def:224 +#: params.def:202 msgid "The maximum amount of memory to be allocated by GCSE" msgstr "" -#: params.def:235 +#: params.def:213 msgid "" "The threshold ratio for performing partial redundancy elimination after " "reload" msgstr "" -#: params.def:242 +#: params.def:220 msgid "" "The threshold ratio of critical edges execution count that permit performing " "redundancy elimination after reload" msgstr "" -#: params.def:253 +#: params.def:231 msgid "The maximum number of instructions to consider to unroll in a loop" msgstr "" -#: params.def:259 +#: params.def:237 msgid "" "The maximum number of instructions to consider to unroll in a loop on average" msgstr "" -#: params.def:264 +#: params.def:242 msgid "The maximum number of unrollings of a single loop" msgstr "" -#: params.def:269 +#: params.def:247 msgid "The maximum number of insns of a peeled loop" msgstr "" -#: params.def:274 +#: params.def:252 msgid "The maximum number of peelings of a single loop" msgstr "" -#: params.def:279 +#: params.def:257 msgid "The maximum number of insns of a completely peeled loop" msgstr "" -#: params.def:284 +#: params.def:262 msgid "" "The maximum number of peelings of a single loop that is peeled completely" msgstr "" -#: params.def:289 +#: params.def:267 msgid "The maximum number of insns of a peeled loop that rolls only once" msgstr "" -#: params.def:295 +#: params.def:273 msgid "The maximum number of insns of an unswitched loop" msgstr "" -#: params.def:300 +#: params.def:278 msgid "The maximum number of unswitchings in a single loop" msgstr "" -#: params.def:307 +#: params.def:285 msgid "" "Bound on the number of iterations the brute force # of iterations analysis " "algorithm evaluates" msgstr "" -#: params.def:313 +#: params.def:291 msgid "Bound on the cost of an expression to compute the number of iterations" msgstr "" -#: params.def:319 +#: params.def:297 msgid "" "A factor for tuning the upper bound that swing modulo scheduler uses for " "scheduling a loop" msgstr "" -#: params.def:323 +#: params.def:301 msgid "" "The number of cycles the swing modulo scheduler considers when checking " "conflicts using DFA" msgstr "" -#: params.def:327 +#: params.def:305 msgid "" "A threshold on the average loop count considered by the swing modulo " "scheduler" msgstr "" -#: params.def:332 +#: params.def:310 msgid "" "Select fraction of the maximal count of repetitions of basic block in " "program given basic block needs to have to be considered hot" msgstr "" -#: params.def:336 +#: params.def:314 msgid "" "Select fraction of the maximal frequency of executions of basic block in " "function given basic block needs to have to be considered hot" msgstr "" -#: params.def:341 +#: params.def:319 msgid "" "Select fraction of the maximal frequency of executions of basic block in " "function given basic block get alignment" msgstr "" -#: params.def:346 +#: params.def:324 msgid "" "Loops iterating at least selected number of iterations will get loop " "alignement." msgstr "" -#: params.def:362 +#: params.def:340 msgid "The maximum number of loop iterations we predict statically" msgstr "" -#: params.def:366 +#: params.def:344 msgid "" "The percentage of function, weighted by execution frequency, that must be " "covered by trace formation. Used when profile feedback is available" msgstr "" -#: params.def:370 +#: params.def:348 msgid "" "The percentage of function, weighted by execution frequency, that must be " "covered by trace formation. Used when profile feedback is not available" msgstr "" -#: params.def:374 +#: params.def:352 msgid "Maximal code growth caused by tail duplication (in percent)" msgstr "" -#: params.def:378 +#: params.def:356 msgid "" "Stop reverse growth if the reverse probability of best edge is less than " "this threshold (in percent)" msgstr "" -#: params.def:382 +#: params.def:360 msgid "" "Stop forward growth if the probability of best edge is less than this " "threshold (in percent). Used when profile feedback is available" msgstr "" -#: params.def:386 +#: params.def:364 msgid "" "Stop forward growth if the probability of best edge is less than this " "threshold (in percent). Used when profile feedback is not available" msgstr "" -#: params.def:392 +#: params.def:370 msgid "The maximum number of incoming edges to consider for crossjumping" msgstr "" -#: params.def:398 +#: params.def:376 msgid "" "The minimum number of matching instructions to consider for crossjumping" msgstr "" -#: params.def:404 +#: params.def:382 msgid "The maximum expansion factor when copying basic blocks" msgstr "" -#: params.def:410 +#: params.def:388 msgid "" "The maximum number of insns to duplicate when unfactoring computed gotos" msgstr "" -#: params.def:416 +#: params.def:394 msgid "The maximum length of path considered in cse" msgstr "" -#: params.def:420 +#: params.def:398 msgid "The maximum instructions CSE process before flushing" msgstr "" -#: params.def:427 +#: params.def:405 msgid "" "The minimum cost of an expensive expression in the loop invariant motion" msgstr "" -#: params.def:436 +#: params.def:414 msgid "" "Bound on number of candidates below that all candidates are considered in iv " "optimizations" msgstr "" -#: params.def:444 +#: params.def:422 msgid "Bound on number of iv uses in loop optimized in iv optimizations" msgstr "" -#: params.def:452 +#: params.def:430 msgid "" "If number of candidates in the set is smaller, we always try to remove " "unused ivs during its optimization" msgstr "" -#: params.def:457 +#: params.def:435 msgid "Bound on size of expressions used in the scalar evolutions analyzer" msgstr "" -#: params.def:462 +#: params.def:440 msgid "Bound on the number of variables in Omega constraint systems" msgstr "" -#: params.def:467 +#: params.def:445 msgid "Bound on the number of inequalities in Omega constraint systems" msgstr "" -#: params.def:472 +#: params.def:450 msgid "Bound on the number of equalities in Omega constraint systems" msgstr "" -#: params.def:477 +#: params.def:455 msgid "Bound on the number of wild cards in Omega constraint systems" msgstr "" -#: params.def:482 +#: params.def:460 msgid "Bound on the size of the hash table in Omega constraint systems" msgstr "" -#: params.def:487 +#: params.def:465 msgid "Bound on the number of keys in Omega constraint systems" msgstr "" -#: params.def:492 +#: params.def:470 msgid "" "When set to 1, use expensive methods to eliminate all redundant constraints" msgstr "" -#: params.def:497 +#: params.def:475 msgid "" "Bound on number of runtime checks inserted by the vectorizer's loop " "versioning for alignment check" msgstr "" -#: params.def:502 +#: params.def:480 msgid "" "Bound on number of runtime checks inserted by the vectorizer's loop " "versioning for alias check" msgstr "" -#: params.def:507 +#: params.def:485 msgid "The maximum memory locations recorded by cselib" msgstr "" -#: params.def:520 +#: params.def:498 msgid "" "Minimum heap expansion to trigger garbage collection, as a percentage of the " "total size of the heap" msgstr "" -#: params.def:525 +#: params.def:503 msgid "Minimum heap size before we start collecting garbage, in kilobytes" msgstr "" -#: params.def:533 +#: params.def:511 msgid "" "The maximum number of instructions to search backward when looking for " "equivalent reload" msgstr "" -#: params.def:538 params.def:548 +#: params.def:516 params.def:526 msgid "" "The maximum number of blocks in a region to be considered for interblock " "scheduling" msgstr "" -#: params.def:543 params.def:553 +#: params.def:521 params.def:531 msgid "" "The maximum number of insns in a region to be considered for interblock " "scheduling" msgstr "" -#: params.def:558 +#: params.def:536 msgid "" "The minimum probability of reaching a source block for interblock " "speculative scheduling" msgstr "" -#: params.def:563 +#: params.def:541 msgid "The maximum number of iterations through CFG to extend regions" msgstr "" -#: params.def:568 +#: params.def:546 msgid "" "The maximum conflict delay for an insn to be considered for speculative " "motion" msgstr "" -#: params.def:573 +#: params.def:551 msgid "" "The minimal probability of speculation success (in percents), so that " "speculative insn will be scheduled." msgstr "" -#: params.def:578 +#: params.def:556 msgid "The maximum size of the lookahead window of selective scheduling" msgstr "" -#: params.def:583 +#: params.def:561 msgid "Maximum number of times that an insn could be scheduled" msgstr "" -#: params.def:588 +#: params.def:566 msgid "" "Maximum number of instructions in the ready list that are considered " "eligible for renaming" msgstr "" -#: params.def:593 +#: params.def:571 msgid "Minimal distance between possibly conflicting store and load" msgstr "" -#: params.def:598 +#: params.def:576 msgid "" "The maximum number of RTL nodes that can be recorded as combiner's last value" msgstr "" -#: params.def:606 +#: params.def:584 msgid "The upper bound for sharing integer constants" msgstr "" -#: params.def:625 +#: params.def:603 msgid "" "Minimum number of virtual mappings to consider switching to full virtual " "renames" msgstr "" -#: params.def:630 +#: params.def:608 msgid "" "Ratio between virtual mappings and virtual symbols to do full virtual renames" msgstr "" -#: params.def:635 +#: params.def:613 msgid "" "The lower bound for a buffer to be considered for stack smashing protection" msgstr "" -#: params.def:653 +#: params.def:631 msgid "" "Maximum number of statements allowed in a block that needs to be duplicated " "when threading jumps" msgstr "" -#: params.def:662 +#: params.def:640 msgid "" "Maximum number of fields in a structure before pointer analysis treats the " "structure as a single variable" msgstr "" -#: params.def:667 +#: params.def:645 msgid "" "The maximum number of instructions ready to be issued to be considered by " "the scheduler during the first scheduling pass" msgstr "" -#: params.def:677 +#: params.def:655 msgid "The number of insns executed before prefetch is completed" msgstr "" -#: params.def:684 +#: params.def:662 msgid "The number of prefetches that can run at the same time" msgstr "" -#: params.def:691 +#: params.def:669 msgid "The size of L1 cache" msgstr "" -#: params.def:698 +#: params.def:676 msgid "The size of L1 cache line" msgstr "" -#: params.def:705 +#: params.def:683 msgid "The size of L2 cache" msgstr "" -#: params.def:716 +#: params.def:694 msgid "Whether to use canonical types" msgstr "" -#: params.def:721 +#: params.def:699 msgid "" "Maximum length of partial antic set when performing tree pre optimization" msgstr "" -#: params.def:731 +#: params.def:709 msgid "Maximum size of a SCC before SCCVN stops processing a function" msgstr "" -#: params.def:736 +#: params.def:714 msgid "max loops number for regional RA" msgstr "" -#: params.def:741 +#: params.def:719 msgid "max size of conflict table in MB" msgstr "" -#: params.def:749 +#: params.def:724 +msgid "" +"The number of registers in each class kept unused by loop invariant motion" +msgstr "" + +#: params.def:732 msgid "" "The maximum ratio between array size and switch branches for a switch " "conversion to take place" msgstr "" -#: params.def:757 +#: params.def:740 msgid "max basic blocks number in loop for loop invariant motion" msgstr "" -#: config/alpha/alpha.c:5054 +#: params.def:746 +msgid "" +"Maximum number of instructions in basic block to be considered for SLP " +"vectorization" +msgstr "" + +#: params.def:751 +msgid "" +"min. ratio of insns to prefetches to enable prefetching for a loop with an " +"unknown trip count" +msgstr "" + +#: params.def:757 +msgid "min. ratio of insns to mem ops to enable prefetching in a loop" +msgstr "" + +#: params.def:764 +msgid "The minimum UID to be used for a nondebug insn" +msgstr "" + +#: params.def:769 +msgid "" +"maximum allowed growth of size of new parameters ipa-sra replaces a pointer " +"to an aggregate with" +msgstr "" + +#: config/alpha/alpha.c:5131 #, c-format msgid "invalid %%H value" msgstr "" -#: config/alpha/alpha.c:5075 config/bfin/bfin.c:1631 +#: config/alpha/alpha.c:5152 config/bfin/bfin.c:1682 #, c-format msgid "invalid %%J value" msgstr "" -#: config/alpha/alpha.c:5105 config/ia64/ia64.c:4765 +#: config/alpha/alpha.c:5182 config/ia64/ia64.c:4978 #, c-format msgid "invalid %%r value" msgstr "" -#: config/alpha/alpha.c:5115 config/ia64/ia64.c:4719 -#: config/rs6000/rs6000.c:12250 config/xtensa/xtensa.c:2242 +#: config/alpha/alpha.c:5192 config/ia64/ia64.c:4932 +#: config/rs6000/rs6000.c:14541 config/xtensa/xtensa.c:2253 #, c-format msgid "invalid %%R value" msgstr "" -#: config/alpha/alpha.c:5121 config/rs6000/rs6000.c:12169 -#: config/xtensa/xtensa.c:2209 +#: config/alpha/alpha.c:5198 config/rs6000/rs6000.c:14460 +#: config/xtensa/xtensa.c:2220 #, c-format msgid "invalid %%N value" msgstr "" -#: config/alpha/alpha.c:5129 config/rs6000/rs6000.c:12197 +#: config/alpha/alpha.c:5206 config/rs6000/rs6000.c:14488 #, c-format msgid "invalid %%P value" msgstr "" -#: config/alpha/alpha.c:5137 +#: config/alpha/alpha.c:5214 #, c-format msgid "invalid %%h value" msgstr "" -#: config/alpha/alpha.c:5145 config/xtensa/xtensa.c:2235 +#: config/alpha/alpha.c:5222 config/xtensa/xtensa.c:2246 #, c-format msgid "invalid %%L value" msgstr "" -#: config/alpha/alpha.c:5184 config/rs6000/rs6000.c:12151 +#: config/alpha/alpha.c:5261 config/rs6000/rs6000.c:14442 #, c-format msgid "invalid %%m value" msgstr "" -#: config/alpha/alpha.c:5192 config/rs6000/rs6000.c:12159 +#: config/alpha/alpha.c:5269 config/rs6000/rs6000.c:14450 #, c-format msgid "invalid %%M value" msgstr "" -#: config/alpha/alpha.c:5236 +#: config/alpha/alpha.c:5313 #, c-format msgid "invalid %%U value" msgstr "" -#: config/alpha/alpha.c:5248 config/alpha/alpha.c:5262 -#: config/rs6000/rs6000.c:12258 +#: config/alpha/alpha.c:5325 config/alpha/alpha.c:5339 +#: config/rs6000/rs6000.c:14549 #, c-format msgid "invalid %%s value" msgstr "" -#: config/alpha/alpha.c:5285 +#: config/alpha/alpha.c:5362 #, c-format msgid "invalid %%C value" msgstr "" -#: config/alpha/alpha.c:5322 config/rs6000/rs6000.c:11986 -#: config/rs6000/rs6000.c:12005 +#: config/alpha/alpha.c:5399 config/rs6000/rs6000.c:14296 #, c-format msgid "invalid %%E value" msgstr "" -#: config/alpha/alpha.c:5347 config/alpha/alpha.c:5395 +#: config/alpha/alpha.c:5424 config/alpha/alpha.c:5472 #, c-format msgid "unknown relocation unspec" msgstr "" -#: config/alpha/alpha.c:5356 config/crx/crx.c:1081 -#: config/rs6000/rs6000.c:12589 config/spu/spu.c:1614 +#: config/alpha/alpha.c:5433 config/crx/crx.c:1092 +#: config/rs6000/rs6000.c:14903 config/spu/spu.c:1647 #, c-format msgid "invalid %%xn code" msgstr "" -#: config/arc/arc.c:1729 config/m32r/m32r.c:1820 +#: config/arc/arc.c:1724 config/m32r/m32r.c:1980 #, c-format msgid "invalid operand to %%R code" msgstr "" -#: config/arc/arc.c:1761 config/m32r/m32r.c:1843 +#: config/arc/arc.c:1756 config/m32r/m32r.c:2003 #, c-format msgid "invalid operand to %%H/%%L code" msgstr "" -#: config/arc/arc.c:1783 config/m32r/m32r.c:1914 +#: config/arc/arc.c:1778 config/m32r/m32r.c:2074 #, c-format msgid "invalid operand to %%U code" msgstr "" -#: config/arc/arc.c:1794 +#: config/arc/arc.c:1789 #, c-format msgid "invalid operand to %%V code" msgstr "" #. Unknown flag. #. Undocumented flag. -#: config/arc/arc.c:1801 config/m32r/m32r.c:1941 config/sparc/sparc.c:7048 +#: config/arc/arc.c:1796 config/m32r/m32r.c:2101 config/sparc/sparc.c:7184 #, c-format msgid "invalid operand output code" msgstr "" -#: config/arm/arm.c:13323 config/arm/arm.c:13341 +#: config/arm/arm.c:14627 config/arm/arm.c:14645 #, c-format msgid "predicated Thumb instruction" msgstr "" -#: config/arm/arm.c:13329 +#: config/arm/arm.c:14633 #, c-format msgid "predicated instruction in conditional sequence" msgstr "" -#: config/arm/arm.c:13499 +#: config/arm/arm.c:14803 #, c-format msgid "invalid shift operand" msgstr "" -#: config/arm/arm.c:13546 config/arm/arm.c:13556 config/arm/arm.c:13566 -#: config/arm/arm.c:13576 config/arm/arm.c:13586 config/arm/arm.c:13625 -#: config/arm/arm.c:13643 config/arm/arm.c:13678 config/arm/arm.c:13697 -#: config/arm/arm.c:13712 config/arm/arm.c:13740 config/arm/arm.c:13747 -#: config/arm/arm.c:13755 config/arm/arm.c:13776 config/arm/arm.c:13783 -#: config/bfin/bfin.c:1644 config/bfin/bfin.c:1651 config/bfin/bfin.c:1658 -#: config/bfin/bfin.c:1665 config/bfin/bfin.c:1674 config/bfin/bfin.c:1681 -#: config/bfin/bfin.c:1688 config/bfin/bfin.c:1695 +#: config/arm/arm.c:14850 config/arm/arm.c:14860 config/arm/arm.c:14870 +#: config/arm/arm.c:14880 config/arm/arm.c:14890 config/arm/arm.c:14929 +#: config/arm/arm.c:14947 config/arm/arm.c:14982 config/arm/arm.c:15001 +#: config/arm/arm.c:15016 config/arm/arm.c:15044 config/arm/arm.c:15051 +#: config/arm/arm.c:15059 config/arm/arm.c:15080 config/arm/arm.c:15087 +#: config/arm/arm.c:15178 config/arm/arm.c:15185 config/bfin/bfin.c:1695 +#: config/bfin/bfin.c:1702 config/bfin/bfin.c:1709 config/bfin/bfin.c:1716 +#: config/bfin/bfin.c:1725 config/bfin/bfin.c:1732 config/bfin/bfin.c:1739 +#: config/bfin/bfin.c:1746 #, c-format msgid "invalid operand for code '%c'" msgstr "" -#: config/arm/arm.c:13638 +#: config/arm/arm.c:14942 #, c-format msgid "instruction never executed" msgstr "" -#: config/arm/arm.c:13850 +#: config/arm/arm.c:15197 #, c-format msgid "missing operand" msgstr "" -#: config/avr/avr.c:1212 +#: config/arm/arm.c:17472 +msgid "function parameters cannot have __fp16 type" +msgstr "" + +#: config/arm/arm.c:17482 +msgid "functions cannot return __fp16 type" +msgstr "" + +#: config/avr/avr.c:1083 #, c-format msgid "address operand requires constraint for X, Y, or Z register" msgstr "" -#: config/avr/avr.c:1324 +#: config/avr/avr.c:1195 msgid "bad address, not (reg+disp):" msgstr "" -#: config/avr/avr.c:1331 +#: config/avr/avr.c:1202 msgid "bad address, not post_inc or pre_dec:" msgstr "" -#: config/avr/avr.c:1342 +#: config/avr/avr.c:1213 msgid "internal compiler error. Bad address:" msgstr "" -#: config/avr/avr.c:1355 +#: config/avr/avr.c:1226 msgid "internal compiler error. Unknown mode:" msgstr "" -#: config/avr/avr.c:1950 config/avr/avr.c:2638 +#: config/avr/avr.c:1813 config/avr/avr.c:2501 msgid "invalid insn:" msgstr "" -#: config/avr/avr.c:1989 config/avr/avr.c:2075 config/avr/avr.c:2124 -#: config/avr/avr.c:2152 config/avr/avr.c:2247 config/avr/avr.c:2416 -#: config/avr/avr.c:2677 config/avr/avr.c:2789 +#: config/avr/avr.c:1852 config/avr/avr.c:1938 config/avr/avr.c:1987 +#: config/avr/avr.c:2015 config/avr/avr.c:2110 config/avr/avr.c:2279 +#: config/avr/avr.c:2540 config/avr/avr.c:2652 msgid "incorrect insn:" msgstr "" -#: config/avr/avr.c:2171 config/avr/avr.c:2332 config/avr/avr.c:2487 -#: config/avr/avr.c:2855 +#: config/avr/avr.c:2034 config/avr/avr.c:2195 config/avr/avr.c:2350 +#: config/avr/avr.c:2718 msgid "unknown move insn:" msgstr "" -#: config/avr/avr.c:3085 +#: config/avr/avr.c:2948 msgid "bad shift insn:" msgstr "" -#: config/avr/avr.c:3201 config/avr/avr.c:3621 config/avr/avr.c:3979 +#: config/avr/avr.c:3064 config/avr/avr.c:3484 config/avr/avr.c:3842 msgid "internal compiler error. Incorrect shift:" msgstr "" -#: config/bfin/bfin.c:1593 +#: config/bfin/bfin.c:1644 #, c-format msgid "invalid %%j value" msgstr "" -#: config/bfin/bfin.c:1786 +#: config/bfin/bfin.c:1837 #, c-format msgid "invalid const_double operand" msgstr "" -#: config/cris/cris.c:504 c-typeck.c:5217 c-typeck.c:5233 c-typeck.c:5250 -#: final.c:3010 final.c:3012 gcc.c:4940 loop-iv.c:2967 loop-iv.c:2976 -#: rtl-error.c:105 toplev.c:610 tree-ssa-loop-niter.c:1882 cp/typeck.c:4743 -#: java/expr.c:411 +#: config/cris/cris.c:520 config/moxie/moxie.c:91 c-typeck.c:5415 +#: c-typeck.c:5431 c-typeck.c:5448 final.c:3090 final.c:3092 fold-const.c:996 +#: gcc.c:5219 loop-iv.c:2968 loop-iv.c:2977 rtl-error.c:105 toplev.c:625 +#: tree-ssa-loop-niter.c:1883 tree-vrp.c:5726 cp/typeck.c:4813 java/expr.c:411 #, gcc-internal-format msgid "%s" msgstr "" -#: config/cris/cris.c:555 +#: config/cris/cris.c:571 msgid "unexpected index-type in cris_print_index" msgstr "" -#: config/cris/cris.c:572 +#: config/cris/cris.c:588 msgid "unexpected base-type in cris_print_base" msgstr "" -#: config/cris/cris.c:688 +#: config/cris/cris.c:704 msgid "invalid operand for 'b' modifier" msgstr "" -#: config/cris/cris.c:705 +#: config/cris/cris.c:721 msgid "invalid operand for 'o' modifier" msgstr "" -#: config/cris/cris.c:724 +#: config/cris/cris.c:740 msgid "invalid operand for 'O' modifier" msgstr "" -#: config/cris/cris.c:757 +#: config/cris/cris.c:773 msgid "invalid operand for 'p' modifier" msgstr "" -#: config/cris/cris.c:796 +#: config/cris/cris.c:812 msgid "invalid operand for 'z' modifier" msgstr "" -#: config/cris/cris.c:860 config/cris/cris.c:894 +#: config/cris/cris.c:876 config/cris/cris.c:910 msgid "invalid operand for 'H' modifier" msgstr "" -#: config/cris/cris.c:870 +#: config/cris/cris.c:886 msgid "bad register" msgstr "" -#: config/cris/cris.c:914 +#: config/cris/cris.c:930 msgid "invalid operand for 'e' modifier" msgstr "" -#: config/cris/cris.c:931 +#: config/cris/cris.c:947 msgid "invalid operand for 'm' modifier" msgstr "" -#: config/cris/cris.c:956 +#: config/cris/cris.c:972 msgid "invalid operand for 'A' modifier" msgstr "" -#: config/cris/cris.c:979 +#: config/cris/cris.c:995 msgid "invalid operand for 'D' modifier" msgstr "" -#: config/cris/cris.c:993 +#: config/cris/cris.c:1009 msgid "invalid operand for 'T' modifier" msgstr "" -#: config/cris/cris.c:1013 +#: config/cris/cris.c:1029 config/moxie/moxie.c:161 msgid "invalid operand modifier letter" msgstr "" -#: config/cris/cris.c:1070 +#: config/cris/cris.c:1086 msgid "unexpected multiplicative operand" msgstr "" -#: config/cris/cris.c:1090 +#: config/cris/cris.c:1106 config/moxie/moxie.c:186 msgid "unexpected operand" msgstr "" -#: config/cris/cris.c:1123 config/cris/cris.c:1133 +#: config/cris/cris.c:1139 config/cris/cris.c:1149 msgid "unrecognized address" msgstr "" -#: config/cris/cris.c:2231 +#: config/cris/cris.c:2257 msgid "unrecognized supposed constant" msgstr "" -#: config/cris/cris.c:2660 config/cris/cris.c:2724 +#: config/cris/cris.c:2686 config/cris/cris.c:2750 msgid "unexpected side-effects in address" msgstr "" #. Can't possibly get a GOT-needing-fixup for a function-call, #. right? -#: config/cris/cris.c:3561 +#: config/cris/cris.c:3587 msgid "Unidentifiable call op" msgstr "" -#: config/cris/cris.c:3613 +#: config/cris/cris.c:3639 #, c-format msgid "PIC register isn't set up" msgstr "" -#: config/fr30/fr30.c:464 +#: config/fr30/fr30.c:481 #, c-format msgid "fr30_print_operand_address: unhandled address" msgstr "" -#: config/fr30/fr30.c:488 +#: config/fr30/fr30.c:505 #, c-format msgid "fr30_print_operand: unrecognized %%p code" msgstr "" -#: config/fr30/fr30.c:508 +#: config/fr30/fr30.c:525 #, c-format msgid "fr30_print_operand: unrecognized %%b code" msgstr "" -#: config/fr30/fr30.c:529 +#: config/fr30/fr30.c:546 #, c-format msgid "fr30_print_operand: unrecognized %%B code" msgstr "" -#: config/fr30/fr30.c:537 +#: config/fr30/fr30.c:554 #, c-format msgid "fr30_print_operand: invalid operand to %%A code" msgstr "" -#: config/fr30/fr30.c:554 +#: config/fr30/fr30.c:571 #, c-format msgid "fr30_print_operand: invalid %%x code" msgstr "" -#: config/fr30/fr30.c:561 +#: config/fr30/fr30.c:578 #, c-format msgid "fr30_print_operand: invalid %%F code" msgstr "" -#: config/fr30/fr30.c:578 +#: config/fr30/fr30.c:595 #, c-format msgid "fr30_print_operand: unknown code" msgstr "" -#: config/fr30/fr30.c:606 config/fr30/fr30.c:615 config/fr30/fr30.c:626 -#: config/fr30/fr30.c:639 +#: config/fr30/fr30.c:623 config/fr30/fr30.c:632 config/fr30/fr30.c:643 +#: config/fr30/fr30.c:656 #, c-format msgid "fr30_print_operand: unhandled MEM" msgstr "" -#: config/frv/frv.c:2589 +#: config/frv/frv.c:2592 msgid "bad insn to frv_print_operand_address:" msgstr "" -#: config/frv/frv.c:2600 +#: config/frv/frv.c:2603 msgid "bad register to frv_print_operand_memory_reference_reg:" msgstr "" -#: config/frv/frv.c:2639 config/frv/frv.c:2649 config/frv/frv.c:2658 -#: config/frv/frv.c:2679 config/frv/frv.c:2684 +#: config/frv/frv.c:2642 config/frv/frv.c:2652 config/frv/frv.c:2661 +#: config/frv/frv.c:2682 config/frv/frv.c:2687 msgid "bad insn to frv_print_operand_memory_reference:" msgstr "" -#: config/frv/frv.c:2770 +#: config/frv/frv.c:2773 #, c-format msgid "bad condition code" msgstr "" -#: config/frv/frv.c:2845 +#: config/frv/frv.c:2848 msgid "bad insn in frv_print_operand, bad const_double" msgstr "" -#: config/frv/frv.c:2906 +#: config/frv/frv.c:2909 msgid "bad insn to frv_print_operand, 'e' modifier:" msgstr "" -#: config/frv/frv.c:2914 +#: config/frv/frv.c:2917 msgid "bad insn to frv_print_operand, 'F' modifier:" msgstr "" -#: config/frv/frv.c:2930 +#: config/frv/frv.c:2933 msgid "bad insn to frv_print_operand, 'f' modifier:" msgstr "" -#: config/frv/frv.c:2944 +#: config/frv/frv.c:2947 msgid "bad insn to frv_print_operand, 'g' modifier:" msgstr "" -#: config/frv/frv.c:2992 +#: config/frv/frv.c:2995 msgid "bad insn to frv_print_operand, 'L' modifier:" msgstr "" -#: config/frv/frv.c:3005 +#: config/frv/frv.c:3008 msgid "bad insn to frv_print_operand, 'M/N' modifier:" msgstr "" -#: config/frv/frv.c:3026 +#: config/frv/frv.c:3029 msgid "bad insn to frv_print_operand, 'O' modifier:" msgstr "" -#: config/frv/frv.c:3044 +#: config/frv/frv.c:3047 msgid "bad insn to frv_print_operand, P modifier:" msgstr "" -#: config/frv/frv.c:3064 +#: config/frv/frv.c:3067 msgid "bad insn in frv_print_operand, z case" msgstr "" -#: config/frv/frv.c:3095 +#: config/frv/frv.c:3098 msgid "bad insn in frv_print_operand, 0 case" msgstr "" -#: config/frv/frv.c:3100 +#: config/frv/frv.c:3103 msgid "frv_print_operand: unknown code" msgstr "" -#: config/frv/frv.c:4469 +#: config/frv/frv.c:4456 msgid "bad output_move_single operand" msgstr "" -#: config/frv/frv.c:4596 +#: config/frv/frv.c:4583 msgid "bad output_move_double operand" msgstr "" -#: config/frv/frv.c:4738 +#: config/frv/frv.c:4725 msgid "bad output_condmove_single operand" msgstr "" @@ -3134,61 +3260,61 @@ msgstr "" msgid " (frv)" msgstr "" -#: config/i386/i386.c:10366 +#: config/i386/i386.c:10758 #, c-format msgid "invalid UNSPEC as operand" msgstr "" -#: config/i386/i386.c:10980 config/i386/i386.c:11055 +#: config/i386/i386.c:11370 config/i386/i386.c:11445 #, c-format msgid "invalid operand size for operand code '%c'" msgstr "" -#: config/i386/i386.c:11050 +#: config/i386/i386.c:11440 #, c-format msgid "invalid operand type used with operand code '%c'" msgstr "" -#: config/i386/i386.c:11130 config/i386/i386.c:11169 config/i386/i386.c:11343 +#: config/i386/i386.c:11520 config/i386/i386.c:11559 #, c-format msgid "operand is not a condition code, invalid operand code 'D'" msgstr "" -#: config/i386/i386.c:11194 +#: config/i386/i386.c:11584 #, c-format msgid "" "operand is neither a constant nor a condition code, invalid operand code 'C'" msgstr "" -#: config/i386/i386.c:11204 +#: config/i386/i386.c:11594 #, c-format msgid "" "operand is neither a constant nor a condition code, invalid operand code 'F'" msgstr "" -#: config/i386/i386.c:11222 +#: config/i386/i386.c:11612 #, c-format msgid "" "operand is neither a constant nor a condition code, invalid operand code 'c'" msgstr "" -#: config/i386/i386.c:11232 +#: config/i386/i386.c:11622 #, c-format msgid "" "operand is neither a constant nor a condition code, invalid operand code 'f'" msgstr "" -#: config/i386/i386.c:11357 +#: config/i386/i386.c:11692 #, c-format msgid "invalid operand code '%c'" msgstr "" -#: config/i386/i386.c:11406 +#: config/i386/i386.c:11741 #, c-format msgid "invalid constraints for operand" msgstr "" -#: config/i386/i386.c:19388 +#: config/i386/i386.c:19309 msgid "unknown insn mode" msgstr "" @@ -3209,195 +3335,201 @@ msgstr "" msgid "environment variable DJGPP points to corrupt file '%s'" msgstr "" -#: config/ia64/ia64.c:4647 +#: config/ia64/ia64.c:4860 #, c-format msgid "invalid %%G mode" msgstr "" -#: config/ia64/ia64.c:4817 +#: config/ia64/ia64.c:5030 #, c-format msgid "ia64_print_operand: unknown code" msgstr "" -#: config/ia64/ia64.c:10495 +#: config/ia64/ia64.c:10748 msgid "invalid conversion from %<__fpreg%>" msgstr "" -#: config/ia64/ia64.c:10498 +#: config/ia64/ia64.c:10751 msgid "invalid conversion to %<__fpreg%>" msgstr "" -#: config/ia64/ia64.c:10511 config/ia64/ia64.c:10522 +#: config/ia64/ia64.c:10764 config/ia64/ia64.c:10775 msgid "invalid operation on %<__fpreg%>" msgstr "" -#: config/iq2000/iq2000.c:3137 +#: config/iq2000/iq2000.c:3130 #, c-format msgid "invalid %%P operand" msgstr "" -#: config/iq2000/iq2000.c:3145 config/rs6000/rs6000.c:12187 +#: config/iq2000/iq2000.c:3138 config/rs6000/rs6000.c:14478 #, c-format msgid "invalid %%p value" msgstr "" -#: config/iq2000/iq2000.c:3201 +#: config/iq2000/iq2000.c:3194 #, c-format msgid "invalid use of %%d, %%x, or %%X" msgstr "" -#: config/m32r/m32r.c:1790 +#: config/m32r/m32r.c:1950 #, c-format msgid "invalid operand to %%s code" msgstr "" -#: config/m32r/m32r.c:1797 +#: config/m32r/m32r.c:1957 #, c-format msgid "invalid operand to %%p code" msgstr "" -#: config/m32r/m32r.c:1852 +#: config/m32r/m32r.c:2012 msgid "bad insn for 'A'" msgstr "" -#: config/m32r/m32r.c:1899 +#: config/m32r/m32r.c:2059 #, c-format msgid "invalid operand to %%T/%%B code" msgstr "" -#: config/m32r/m32r.c:1922 +#: config/m32r/m32r.c:2082 #, c-format msgid "invalid operand to %%N code" msgstr "" -#: config/m32r/m32r.c:1955 +#: config/m32r/m32r.c:2115 msgid "pre-increment address is not a register" msgstr "" -#: config/m32r/m32r.c:1962 +#: config/m32r/m32r.c:2122 msgid "pre-decrement address is not a register" msgstr "" -#: config/m32r/m32r.c:1969 +#: config/m32r/m32r.c:2129 msgid "post-increment address is not a register" msgstr "" -#: config/m32r/m32r.c:2045 config/m32r/m32r.c:2059 -#: config/rs6000/rs6000.c:20957 +#: config/m32r/m32r.c:2205 config/m32r/m32r.c:2219 +#: config/rs6000/rs6000.c:23575 msgid "bad address" msgstr "" -#: config/m32r/m32r.c:2064 +#: config/m32r/m32r.c:2224 msgid "lo_sum not of register" msgstr "" #. !!!! SCz wrong here. -#: config/m68hc11/m68hc11.c:3181 config/m68hc11/m68hc11.c:3559 +#: config/m68hc11/m68hc11.c:3204 config/m68hc11/m68hc11.c:3582 msgid "move insn not handled" msgstr "" -#: config/m68hc11/m68hc11.c:3405 config/m68hc11/m68hc11.c:3489 -#: config/m68hc11/m68hc11.c:3762 +#: config/m68hc11/m68hc11.c:3428 config/m68hc11/m68hc11.c:3512 +#: config/m68hc11/m68hc11.c:3785 msgid "invalid register in the move instruction" msgstr "" -#: config/m68hc11/m68hc11.c:3439 +#: config/m68hc11/m68hc11.c:3462 msgid "invalid operand in the instruction" msgstr "" -#: config/m68hc11/m68hc11.c:3736 +#: config/m68hc11/m68hc11.c:3759 msgid "invalid register in the instruction" msgstr "" -#: config/m68hc11/m68hc11.c:3769 +#: config/m68hc11/m68hc11.c:3792 msgid "operand 1 must be a hard register" msgstr "" -#: config/m68hc11/m68hc11.c:3783 +#: config/m68hc11/m68hc11.c:3806 msgid "invalid rotate insn" msgstr "" -#: config/m68hc11/m68hc11.c:4207 +#: config/m68hc11/m68hc11.c:4234 msgid "registers IX, IY and Z used in the same INSN" msgstr "" -#: config/m68hc11/m68hc11.c:4540 config/m68hc11/m68hc11.c:4840 +#: config/m68hc11/m68hc11.c:4567 config/m68hc11/m68hc11.c:4867 msgid "cannot do z-register replacement" msgstr "" -#: config/m68hc11/m68hc11.c:4903 +#: config/m68hc11/m68hc11.c:4930 msgid "invalid Z register replacement for insn" msgstr "" -#: config/mips/mips.c:7131 config/mips/mips.c:7152 config/mips/mips.c:7264 +#: config/mep/mep.c:3414 +#, c-format +msgid "invalid %%L code" +msgstr "" + +#: config/mips/mips.c:7370 config/mips/mips.c:7391 config/mips/mips.c:7503 #, c-format msgid "'%%%c' is not a valid operand prefix" msgstr "" -#: config/mips/mips.c:7201 config/mips/mips.c:7208 config/mips/mips.c:7215 -#: config/mips/mips.c:7222 config/mips/mips.c:7282 +#: config/mips/mips.c:7440 config/mips/mips.c:7447 config/mips/mips.c:7454 +#: config/mips/mips.c:7461 config/mips/mips.c:7521 config/mips/mips.c:7535 +#: config/mips/mips.c:7548 config/mips/mips.c:7557 #, c-format msgid "invalid use of '%%%c'" msgstr "" -#: config/mips/mips.c:7534 +#: config/mips/mips.c:7779 msgid "mips_debugger_offset called with non stack/frame/arg pointer" msgstr "" -#: config/mmix/mmix.c:1484 config/mmix/mmix.c:1614 +#: config/mmix/mmix.c:1494 config/mmix/mmix.c:1624 msgid "MMIX Internal: Expected a CONST_INT, not this" msgstr "" -#: config/mmix/mmix.c:1563 +#: config/mmix/mmix.c:1573 msgid "MMIX Internal: Bad value for 'm', not a CONST_INT" msgstr "" -#: config/mmix/mmix.c:1582 +#: config/mmix/mmix.c:1592 msgid "MMIX Internal: Expected a register, not this" msgstr "" -#: config/mmix/mmix.c:1592 +#: config/mmix/mmix.c:1602 msgid "MMIX Internal: Expected a constant, not this" msgstr "" #. We need the original here. -#: config/mmix/mmix.c:1676 +#: config/mmix/mmix.c:1686 msgid "MMIX Internal: Cannot decode this operand" msgstr "" -#: config/mmix/mmix.c:1733 +#: config/mmix/mmix.c:1743 msgid "MMIX Internal: This is not a recognized address" msgstr "" -#: config/mmix/mmix.c:2666 +#: config/mmix/mmix.c:2620 msgid "MMIX Internal: Trying to output invalidly reversed condition:" msgstr "" -#: config/mmix/mmix.c:2673 +#: config/mmix/mmix.c:2627 msgid "MMIX Internal: What's the CC of this?" msgstr "" -#: config/mmix/mmix.c:2677 +#: config/mmix/mmix.c:2631 msgid "MMIX Internal: What is the CC of this?" msgstr "" -#: config/mmix/mmix.c:2741 +#: config/mmix/mmix.c:2695 msgid "MMIX Internal: This is not a constant:" msgstr "" -#: config/picochip/picochip.c:2406 +#: config/picochip/picochip.c:2410 msgid "picochip_print_memory_address - Operand isn't memory based" msgstr "" -#: config/picochip/picochip.c:2665 +#: config/picochip/picochip.c:2669 msgid "Unknown mode in print_operand (CONST_DOUBLE) :" msgstr "" -#: config/picochip/picochip.c:2711 config/picochip/picochip.c:2743 +#: config/picochip/picochip.c:2715 config/picochip/picochip.c:2747 msgid "Bad address, not (reg+disp):" msgstr "" -#: config/picochip/picochip.c:2757 +#: config/picochip/picochip.c:2761 msgid "Bad address, not register:" msgstr "" @@ -3411,407 +3543,451 @@ msgstr "" msgid "Try running '%s' in the shell to raise its limit.\n" msgstr "" -#: config/rs6000/rs6000.c:12014 +#: config/rs6000/rs6000.c:2391 +msgid "-mvsx requires hardware floating point" +msgstr "" + +#: config/rs6000/rs6000.c:2396 +msgid "-mvsx and -mpaired are incompatible" +msgstr "" + +#: config/rs6000/rs6000.c:2401 +msgid "-mvsx used with little endian code" +msgstr "" + +#: config/rs6000/rs6000.c:2403 +msgid "-mvsx needs indexed addressing" +msgstr "" + +#: config/rs6000/rs6000.c:6610 +msgid "bad move" +msgstr "" + +#: config/rs6000/rs6000.c:14277 +#, c-format +msgid "invalid %%c value" +msgstr "" + +#: config/rs6000/rs6000.c:14305 #, c-format msgid "invalid %%f value" msgstr "" -#: config/rs6000/rs6000.c:12023 +#: config/rs6000/rs6000.c:14314 #, c-format msgid "invalid %%F value" msgstr "" -#: config/rs6000/rs6000.c:12032 +#: config/rs6000/rs6000.c:14323 #, c-format msgid "invalid %%G value" msgstr "" -#: config/rs6000/rs6000.c:12067 +#: config/rs6000/rs6000.c:14358 #, c-format msgid "invalid %%j code" msgstr "" -#: config/rs6000/rs6000.c:12077 +#: config/rs6000/rs6000.c:14368 #, c-format msgid "invalid %%J code" msgstr "" -#: config/rs6000/rs6000.c:12087 +#: config/rs6000/rs6000.c:14378 #, c-format msgid "invalid %%k value" msgstr "" -#: config/rs6000/rs6000.c:12107 config/xtensa/xtensa.c:2228 +#: config/rs6000/rs6000.c:14398 config/xtensa/xtensa.c:2239 #, c-format msgid "invalid %%K value" msgstr "" -#: config/rs6000/rs6000.c:12177 +#: config/rs6000/rs6000.c:14468 #, c-format msgid "invalid %%O value" msgstr "" -#: config/rs6000/rs6000.c:12224 +#: config/rs6000/rs6000.c:14515 #, c-format msgid "invalid %%q value" msgstr "" -#: config/rs6000/rs6000.c:12268 +#: config/rs6000/rs6000.c:14559 #, c-format msgid "invalid %%S value" msgstr "" -#: config/rs6000/rs6000.c:12308 +#: config/rs6000/rs6000.c:14599 #, c-format msgid "invalid %%T value" msgstr "" -#: config/rs6000/rs6000.c:12318 +#: config/rs6000/rs6000.c:14609 #, c-format msgid "invalid %%u value" msgstr "" -#: config/rs6000/rs6000.c:12327 config/xtensa/xtensa.c:2198 +#: config/rs6000/rs6000.c:14618 config/xtensa/xtensa.c:2209 #, c-format msgid "invalid %%v value" msgstr "" -#: config/rs6000/rs6000.c:12548 +#: config/rs6000/rs6000.c:14717 config/xtensa/xtensa.c:2260 +#, c-format +msgid "invalid %%x value" +msgstr "" + +#: config/rs6000/rs6000.c:14862 #, c-format msgid "invalid %%y value, try using the 'Z' constraint" msgstr "" -#: config/rs6000/rs6000.c:22826 +#: config/rs6000/rs6000.c:25542 msgid "AltiVec argument passed to unprototyped function" msgstr "" -#: config/s390/s390.c:4934 +#: config/s390/s390.c:4944 #, c-format msgid "cannot decompose address" msgstr "" -#: config/s390/s390.c:5147 +#: config/s390/s390.c:5167 msgid "UNKNOWN in print_operand !?" msgstr "" -#: config/score/score3.c:1262 config/score/score3.c:1282 -#: config/score/score7.c:1253 +#: config/score/score3.c:1282 config/score/score3.c:1302 +#: config/score/score7.c:1270 #, c-format msgid "invalid operand for code: '%c'" msgstr "" -#: config/sh/sh.c:785 +#: config/sh/sh.c:1114 #, c-format msgid "invalid operand to %%R" msgstr "" -#: config/sh/sh.c:812 +#: config/sh/sh.c:1141 #, c-format msgid "invalid operand to %%S" msgstr "" -#: config/sh/sh.c:8384 +#: config/sh/sh.c:8877 msgid "created and used with different architectures / ABIs" msgstr "" -#: config/sh/sh.c:8386 +#: config/sh/sh.c:8879 msgid "created and used with different ABIs" msgstr "" -#: config/sh/sh.c:8388 +#: config/sh/sh.c:8881 msgid "created and used with different endianness" msgstr "" -#: config/sparc/sparc.c:6856 config/sparc/sparc.c:6862 +#: config/sparc/sparc.c:6992 config/sparc/sparc.c:6998 #, c-format msgid "invalid %%Y operand" msgstr "" -#: config/sparc/sparc.c:6932 +#: config/sparc/sparc.c:7068 #, c-format msgid "invalid %%A operand" msgstr "" -#: config/sparc/sparc.c:6942 +#: config/sparc/sparc.c:7078 #, c-format msgid "invalid %%B operand" msgstr "" -#: config/sparc/sparc.c:6981 +#: config/sparc/sparc.c:7117 #, c-format msgid "invalid %%c operand" msgstr "" -#: config/sparc/sparc.c:7003 +#: config/sparc/sparc.c:7139 #, c-format msgid "invalid %%d operand" msgstr "" -#: config/sparc/sparc.c:7020 +#: config/sparc/sparc.c:7156 #, c-format msgid "invalid %%f operand" msgstr "" -#: config/sparc/sparc.c:7034 +#: config/sparc/sparc.c:7170 #, c-format msgid "invalid %%s operand" msgstr "" -#: config/sparc/sparc.c:7088 +#: config/sparc/sparc.c:7224 #, c-format msgid "long long constant not a valid immediate operand" msgstr "" -#: config/sparc/sparc.c:7091 +#: config/sparc/sparc.c:7227 #, c-format msgid "floating point constant not a valid immediate operand" msgstr "" -#: config/stormy16/stormy16.c:1746 config/stormy16/stormy16.c:1817 +#: config/stormy16/stormy16.c:1755 config/stormy16/stormy16.c:1826 #, c-format msgid "'B' operand is not constant" msgstr "" -#: config/stormy16/stormy16.c:1773 +#: config/stormy16/stormy16.c:1782 #, c-format msgid "'B' operand has multiple bits set" msgstr "" -#: config/stormy16/stormy16.c:1799 +#: config/stormy16/stormy16.c:1808 #, c-format msgid "'o' operand is not constant" msgstr "" -#: config/stormy16/stormy16.c:1831 +#: config/stormy16/stormy16.c:1840 #, c-format msgid "xstormy16_print_operand: unknown code" msgstr "" -#: config/v850/v850.c:372 +#: config/v850/v850.c:400 msgid "const_double_split got a bad insn:" msgstr "" -#: config/v850/v850.c:936 +#: config/v850/v850.c:971 msgid "output_move_single:" msgstr "" -#: config/vax/vax.c:382 +#: config/vax/vax.c:399 #, c-format msgid "symbol used with both base and indexed registers" msgstr "" -#: config/vax/vax.c:391 +#: config/vax/vax.c:408 #, c-format msgid "symbol with offset used in PIC mode" msgstr "" -#: config/vax/vax.c:475 +#: config/vax/vax.c:494 #, c-format msgid "symbol used as immediate operand" msgstr "" -#: config/vax/vax.c:1469 +#: config/vax/vax.c:1519 msgid "illegal operand detected" msgstr "" -#: config/xtensa/xtensa.c:696 config/xtensa/xtensa.c:728 -#: config/xtensa/xtensa.c:737 +#: config/xtensa/xtensa.c:705 config/xtensa/xtensa.c:737 +#: config/xtensa/xtensa.c:746 msgid "bad test" msgstr "" -#: config/xtensa/xtensa.c:2186 +#: config/xtensa/xtensa.c:2197 #, c-format msgid "invalid %%D value" msgstr "" -#: config/xtensa/xtensa.c:2223 +#: config/xtensa/xtensa.c:2234 msgid "invalid mask" msgstr "" -#: config/xtensa/xtensa.c:2249 -#, c-format -msgid "invalid %%x value" -msgstr "" - -#: config/xtensa/xtensa.c:2256 +#: config/xtensa/xtensa.c:2267 #, c-format msgid "invalid %%d value" msgstr "" -#: config/xtensa/xtensa.c:2277 config/xtensa/xtensa.c:2287 +#: config/xtensa/xtensa.c:2288 config/xtensa/xtensa.c:2298 #, c-format msgid "invalid %%t/%%b value" msgstr "" -#: config/xtensa/xtensa.c:2329 +#: config/xtensa/xtensa.c:2340 msgid "invalid address" msgstr "" -#: config/xtensa/xtensa.c:2354 +#: config/xtensa/xtensa.c:2365 msgid "no register in address" msgstr "" -#: config/xtensa/xtensa.c:2362 +#: config/xtensa/xtensa.c:2373 msgid "address offset not a constant" msgstr "" -#: cp/call.c:2604 +#: cp/call.c:2773 msgid "candidates are:" msgstr "" -#: cp/call.c:6904 +#: cp/call.c:7256 msgid "candidate 1:" msgstr "" -#: cp/call.c:6905 +#: cp/call.c:7257 msgid "candidate 2:" msgstr "" -#: cp/cxx-pretty-print.c:173 cp/error.c:916 objc/objc-act.c:7078 +#: cp/cxx-pretty-print.c:173 cp/error.c:943 objc/objc-act.c:7141 msgid "" msgstr "" -#: cp/cxx-pretty-print.c:2055 +#: cp/cxx-pretty-print.c:2056 msgid "template-parameter-" msgstr "" -#: cp/decl2.c:676 +#: cp/decl2.c:683 msgid "candidates are: %+#D" msgstr "" -#: cp/decl2.c:678 +#: cp/decl2.c:685 msgid "candidate is: %+#D" msgstr "" -#: cp/error.c:305 +#: cp/error.c:322 msgid "" msgstr "" -#: cp/error.c:346 +#: cp/error.c:363 msgid "" msgstr "" -#: cp/error.c:348 +#: cp/error.c:365 msgid "" msgstr "" -#: cp/error.c:488 +#: cp/error.c:505 msgid "" msgstr "" -#: cp/error.c:587 +#: cp/error.c:604 #, c-format msgid "" msgstr "" -#: cp/error.c:709 +#. A lambda's "type" is essentially its signature. +#: cp/error.c:609 +msgid "" msgstr "" -#: cp/error.c:819 +#: cp/error.c:846 #, c-format msgid "(static initializers for %s)" msgstr "" -#: cp/error.c:821 +#: cp/error.c:848 #, c-format msgid "(static destructors for %s)" msgstr "" -#: cp/error.c:891 +#: cp/error.c:918 msgid "vtable for " msgstr "" -#: cp/error.c:903 +#: cp/error.c:930 msgid " " msgstr "" -#: cp/error.c:1029 +#: cp/error.c:1056 msgid "" msgstr "" -#: cp/error.c:1069 +#: cp/error.c:1096 msgid "" msgstr "" -#: cp/error.c:1299 +#: cp/error.c:1336 msgid "with" msgstr "" -#: cp/error.c:1464 cp/error.c:1484 +#: cp/error.c:1504 cp/error.c:1524 msgid "